using System;
using System.Reflection;
using System.CodeDom;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Web.Services.Description;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace Thinktecture.Tools.Web.Services.CodeGeneration
{
	/// <summary>
	/// Summary description for CodeDecorator.
	/// </summary>
	internal class CodeDecorator
	{
		internal static bool namingConventionsApplicable = true;
		internal const string AsyncNamingPattern = @"((.*)(Async)\d*)$|((.*)(Async))$";

        private CodeDecorator() {}
	    
		#region Helper Methods

		/// <summary>
		/// Checks wheter a specified type is an value type or a reference type.
		/// This check is performed only on the custom types defined in the CodeDOM namespace. (i.e. Customer)
		/// This check is not performed for the intrinsic types in the .Net Fx (i.e. string).
		/// </summary>
		/// <param name="ptype">Name of the type.</param>
		/// <param name="pcns">CodeDOM namespace with the type declaraction (If available).</param>
		/// <returns>
		/// A boolean value indicating the result.
		/// true:  Type is a value type.
		/// false: Type is a reference type.
		/// </returns>
		/// <author>BDS - thinktecture</author>
		private static bool IsValueType(string ptype, CodeNamespace pcns)
		{
			// Validate the input parameters.
			Debug.Assert((ptype != null),"Parameter ptype could not be null");
			Debug.Assert((ptype.Length != 0),"Parameter ptype could not be a 0 length string");
			Debug.Assert((pcns != null),"Parameter pcns could not be null");

			bool valuetype = true;
			
			//
			// Logic:
			// First try to get the type info from Type.GetType() method. This will return null
			// if the type info is not available. Then iterate through the types in the CodeDOM
			// namespace to see whether the type is declaration is there.
			// Once the type info is found, turn on the addnullcheck flag, if it is not a 
			// value type or an enum.
			//
			foreach(CodeTypeDeclaration td in pcns.Types)
			{
				if(td.Name == ptype)
				{
					valuetype = (td.IsStruct || td.IsEnum);
					break;
				}
			}
			return valuetype;
		}

		private static string FindArrayTypeName(XmlSchemas schemas, string msgName, 
			string paramName, ref string xmlNamespace)
		{
			string typeName = "";
			foreach(XmlSchema xmlSchema in schemas)
			{
				foreach (XmlSchemaObject xmlObj in xmlSchema.Items)
				{
					if(xmlObj is XmlSchemaAnnotated) 
					{
						if (xmlObj is XmlSchemaElement)
						{
							XmlSchemaElement xse = (XmlSchemaElement)xmlObj;
							if(xse.Name == msgName && xse.SchemaType != null && 
								xse.SchemaType is XmlSchemaComplexType)
							{
								XmlSchemaComplexType ct = xse.SchemaType as XmlSchemaComplexType;				
								if(ct.Particle != null && ct.Particle is XmlSchemaSequence)
								{
									if(((XmlSchemaSequence)ct.Particle).Items.Count == 1)
									{
										typeName = xse.Name;
										return typeName;
									}
									else
									{
										for(int itemIndex = 0; 
											itemIndex < ((XmlSchemaSequence)ct.Particle).Items.Count;
											itemIndex++)
										{
											XmlSchemaElement element = 
												((XmlSchemaSequence)ct.Particle).Items[itemIndex] as 
												XmlSchemaElement;
											if(element.Name == paramName)
											{
												typeName = element.SchemaTypeName.Name;
												xmlNamespace = element.SchemaTypeName.Namespace;
												
												return typeName;
											}
										}
									}									
								}
							}	
						}
					}
				}
			}

			return typeName;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="methodName"></param>
		/// <param name="output"></param>
		/// <param name="memberName"></param>
		/// <param name="xmlNamespace"></param>
		/// <returns></returns>
		private static string GetArrayWrapperName(string methodName, bool output, 
			ServiceDescriptionImporter sdi, string paramName, ref string xmlNamespace)
		{
			ServiceDescription desc = sdi.ServiceDescriptions[0];
			PortType portType = desc.PortTypes[0];
			
			string msgName = "";
			string typeName = "";
			string messageNamespace = "";

			foreach(Operation operation in portType.Operations)
			{
				if(operation.Name == methodName)
				{
					if(!output)
					{
						Message msgIn = desc.Messages[operation.Messages.Input.Message.Name];						
						msgName = msgIn.Parts[0].Element.Name;
						messageNamespace = msgIn.Parts[0].Element.Namespace;
					}
					else
					{
						Message msgOut = desc.Messages[operation.Messages.Output.Message.Name];
						msgName = msgOut.Parts[0].Element.Name;
						messageNamespace = msgOut.Parts[0].Element.Namespace;
					}

					// Call the FindArrayTypeMemberName function to traverse the available schemas 
					// and find the appropriate member name for the array wrapper.
					typeName = FindArrayTypeName(sdi.Schemas, msgName, paramName, ref xmlNamespace);
										
					if(typeName == "")
					{
						typeName = FindArrayTypeName(desc.Types.Schemas, msgName, paramName, ref xmlNamespace);
					}

					// If the xmlNamespace if not set by FindArrayTypeName method, set it to the namespace 
					// name of the In/Out Message namespace.
					if(xmlNamespace == "")
					{
						xmlNamespace = messageNamespace;
					}

					break;
				}
			}
			return typeName;
		}
		
		
		/// <summary>
		/// 
		/// </summary>
		/// <param name="wrapperName"></param>
		/// <param name="xmlNamespace"></param>
		/// <param name="typeName"></param>
		/// <param name="xmlElementName"></param>
		/// <returns></returns>
		private static CodeTypeDeclaration GenerateArrayWrapper(string wrapperName, 
			string wrapperNamespace, string memberName, string typeName, 
			CodeAttributeDeclarationCollection memberAttributes)
		{
			CodeTypeDeclaration arrayWrapper = new CodeTypeDeclaration(wrapperName);
			arrayWrapper.TypeAttributes = TypeAttributes.Public | TypeAttributes.Class;

			CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(
				"System.Xml.Serialization.XmlTypeAttribute", 
				new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(wrapperNamespace)), 
				new CodeAttributeArgument("TypeName", new CodePrimitiveExpression(wrapperName)));
			
			arrayWrapper.CustomAttributes.Add(attribute);
			
			CodeMemberField field = new CodeMemberField();
			field.Name = memberName;
			field.Type.BaseType = typeName;
			field.Type.ArrayRank = 1;
			field.Type.ArrayElementType = new CodeTypeReference(typeName);
			field.Attributes = MemberAttributes.Public;
			field.CustomAttributes.AddRange(memberAttributes);
			arrayWrapper.Members.Add(field);
	
			return arrayWrapper;
		}

		private static bool WrapArrayParameters(ServiceDescriptionImporter sdi)
		{			
			Debug.Assert((sdi != null),"Parameter sdi could not be null");
			Debug.Assert((sdi.ServiceDescriptions.Count != 0), "Could not find the service description.");
			ServiceDescription serviceDescription = sdi.ServiceDescriptions[0];
			
			// Rule No 1: Each message must have only one <part>.
			foreach(Message message in serviceDescription.Messages)
			{
				if(message.Parts.Count != 1)
				{
					return false;
				}
			}

			// Rule No 2: For soap bindings the binding style must be 'Document' and encoding must be 'Literal'.

			// Obtain a reference to the one and only binding we have.
			if (serviceDescription.Bindings.Count <= 0)
			{
				return false;
			}

			Binding binding = serviceDescription.Bindings[0];
			
			// Search for the soap binding style and return false if it is not 'Document'
			foreach(object extension in binding.Extensions)
			{                
				SoapBinding soapBinding = extension as SoapBinding;
				if(soapBinding != null)
				{
					if(soapBinding.Style != SoapBindingStyle.Document)
					{
						return false;
					}
				}
			}

			// Validate the operation bindings.
			foreach(OperationBinding operationBinding in binding.Operations)
			{
				// Validate the soap binding style in soap operation binding extension.
				foreach(ServiceDescriptionFormatExtension extension in operationBinding.Extensions)
				{
					SoapOperationBinding soapOperationBinding = extension as SoapOperationBinding;

					if(soapOperationBinding != null)
					{
						if(soapOperationBinding.Style != SoapBindingStyle.Document)
						{
							return false;
						}
					}
				}
			
				// Validate the 'use' element in input message body and the headers.
				foreach(ServiceDescriptionFormatExtension extension in operationBinding.Input.Extensions)
				{
					// Check for a header.
					SoapHeaderBinding headerBinding = extension as SoapHeaderBinding;
					if(headerBinding != null)
					{
						if(headerBinding.Use != SoapBindingUse.Literal)
						{
							return false;
						}
						continue;
					}
					
					// Check for the body.
					SoapBodyBinding bodyBinding = extension as SoapBodyBinding;
					if(bodyBinding != null)
					{
						if(bodyBinding.Use != SoapBindingUse.Literal)
						{
							return false;
						}

						continue;
					}
				}
	
				// Validate the 'use' element in output message body and the headers.
				if(operationBinding.Output != null)
				{
					foreach(ServiceDescriptionFormatExtension extension in operationBinding.Output.Extensions)
					{
						// Check for the header.
						SoapHeaderBinding headerBinding = extension as SoapHeaderBinding;
						if(headerBinding != null)
						{
							if(headerBinding.Use != SoapBindingUse.Literal)
							{
								return false;
							}
							continue;
						}
					
						// Check for the body.
						SoapBodyBinding bodyBinding = extension as SoapBodyBinding;
						if(bodyBinding != null)
						{
							if(bodyBinding.Use != SoapBindingUse.Literal)
							{
								return false;
							}

							continue;
						}
					}
				}
			}

			return true;
		}


		/// <summary>
		/// Builds and returns a string using the values available in thespecified 
		/// array of XmlNode objects.
		/// </summary>
		/// <param name="nodes">XmlNode array to use.</param>
		/// <returns>A string value.</returns>
		private static string GetStringFromXmlNodes(XmlNode[] nodes)
		{
			string retvalue = "";

            if (nodes != null)
            {
                foreach (XmlNode node in nodes)
                {
                    retvalue += node.Value + "\n";
                }
                retvalue = retvalue.TrimEnd('\n');
            }
			
			return retvalue;
		}

		/// <summary>
		/// Checks whether a given attribute exists in an attributes collection.
		/// </summary>
		/// <param name="attributeName">Name of the attribute search for.</param>
		/// <param name="attributes">Collection of attributes to search.</param>
		/// <returns>A reference to the attribute if it is found. Returns null otherwise.</returns>
		private static CodeAttributeDeclaration HasAttribute(string attributeName, 
			CodeAttributeDeclarationCollection attributes)
		{
			if(attributes != null)
			{
				foreach(CodeAttributeDeclaration attribute in attributes)
				{
					if(attribute.Name == attributeName)
					{
						return attribute;
					}
				}
			}
			return null;
		}

        /// <summary>
        /// Checks whether a given attribute and an attribute argument exists in an 
        /// attribute collection.
        /// </summary>        
        private static CodeAttributeArgument HasAttributeArgument(string attributeName,
            string argumentName, CodeAttributeDeclarationCollection attributes)
        {
            Debug.Assert(!string.IsNullOrEmpty(attributeName), "attributeName argument could not be null or an empty string.");
            Debug.Assert(!string.IsNullOrEmpty(argumentName), "argumentName argument could not be null or an empty string.");
            Debug.Assert(attributes != null, "attributes argument could not be null.");

            CodeAttributeDeclaration attribute = HasAttribute(attributeName, attributes);

            if (attribute != null)
            {
                foreach (CodeAttributeArgument argument in attribute.Arguments)
                {
                    if (argument.Name.Equals(argumentName, StringComparison.CurrentCultureIgnoreCase))
                    {
                        return argument;
                    }
                }
            }

            return null;
        }
        
		/// <summary>
		/// This method checks whether a given method is useing 'Wrapped' style Soap parameters.
		/// </summary>
		/// <param name="method"></param>
		/// <returns></returns>
		private static bool IsDocLitWrapped(CodeMemberMethod method)
		{
			foreach(CodeAttributeDeclaration attribute in method.CustomAttributes)
			{
				if(attribute.Name == "System.Web.Services.Protocols.SoapDocumentMethodAttribute")
				{
					foreach(CodeAttributeArgument argument in attribute.Arguments)
					{
						if(argument.Name == "ParameterStyle")
						{
							CodeFieldReferenceExpression style = argument.Value as CodeFieldReferenceExpression;
							if(style != null)
							{
								CodeTypeReferenceExpression typeRef = 
									style.TargetObject as CodeTypeReferenceExpression;
								if(typeRef != null && 
									typeRef.Type.BaseType == "System.Web.Services.Protocols.SoapParameterStyle" && 
									style.FieldName == "Wrapped")
								{
									return true;
								}
							}

							break;
						}
					}

					break;
				}
			}

			return false;
		}
		
		
		private static bool IsJaggedArray(CodeAttributeDeclarationCollection attributes)
		{
			foreach(CodeAttributeDeclaration attribute in attributes)
			{
				if(attribute.Name == "System.Xml.Serialization.XmlArrayItemAttribute")
				{
					foreach(CodeAttributeArgument arg in attribute.Arguments)
					{
						if(arg.Name == "NestingLevel")
						{
							CodePrimitiveExpression valueExp = arg.Value as CodePrimitiveExpression;
							if(valueExp != null)
							{
								int value = (int)valueExp.Value;
								if(value > 0)
								{
									return true;
								}
							}
						}
					}
				}
			}
			return false;
		}
		#endregion

		#region Public Static Members

		// BDS: Added a new parameter to refer a CodeDOM namespace object.
		// Reason: A helper method - "IsValueType" used inside this function requires a reference to
		// the CodeNamespace object.
		// 08-04-2005 - BDS
		// Changed this procedure to avoid type name collisions.
		internal static CodeTypeDeclaration GetCollectionForType(CodeTypeReference forType, CodeNamespace pcns)
		{
			string forTypeString = forType.BaseType;
			string ctypeName;
			int counter = 0;

			if(forTypeString.StartsWith("System."))
				forTypeString = forTypeString.Substring(forTypeString.LastIndexOf('.') + 1, forTypeString.Length - 1 - forTypeString.LastIndexOf('.'));
			
			// BDS: Is there any other type with the same name?
			ctypeName = forTypeString + "Collection";
			
			StartCollisionCheck:
			foreach(CodeTypeDeclaration decl in pcns.Types)
			{
				if(string.Compare(ctypeName, decl.Name, false, CultureInfo.CurrentCulture) == 0)
				{
					counter++;
					ctypeName = 
						string.Format("{0}{1}{2}", forTypeString, "Collection", counter); // Assign the new name.
					goto StartCollisionCheck; // Restart the collision check.
				}
			}

			CodeTypeDeclaration col = new CodeTypeDeclaration(ctypeName);
			col.BaseTypes.Add(typeof(CollectionBase));
			col.Attributes = MemberAttributes.Final | MemberAttributes.Public;
		
			//
			// BDS: Validate parameters.
			// 
			// If the type is a reference type then validate for nullity.
			CodeConditionStatement nullchk = null;
			if(!IsValueType(forType.BaseType,pcns))
			{				
				nullchk = new CodeConditionStatement();
				CodeBinaryOperatorExpression condition = 
					new CodeBinaryOperatorExpression(new CodeArgumentReferenceExpression("value"),
					CodeBinaryOperatorType.IdentityEquality, 
					new CodePrimitiveExpression(null));
				nullchk.Condition = condition;
					
				// Create the throw exception statment.
				CodeThrowExceptionStatement throwException = new CodeThrowExceptionStatement(
					new CodeObjectCreateExpression(
					new CodeTypeReference(typeof(ArgumentNullException)),
					new CodePrimitiveExpression[1] {new CodePrimitiveExpression("value")}));
				// Add the exception statement to true statements of the condition.
				nullchk.TrueStatements.Add(throwException); 
			}
			// 
			// End of validation.
			//

			// Add method
			CodeMemberMethod add = new CodeMemberMethod();
			add.Attributes = MemberAttributes.Final | MemberAttributes.Public;
			add.Name = "Add";
			add.ReturnType = new CodeTypeReference(typeof(int));
			add.Parameters.Add(new CodeParameterDeclarationExpression (
				forType, "value"));
			
			if(nullchk != null) add.Statements.Add(nullchk); // BDS: Add null check for the value parameter.

			// Generates: return base.InnerList.Add(value);
			add.Statements.Add( new CodeMethodReturnStatement(
				new CodeMethodInvokeExpression( 
				new CodePropertyReferenceExpression(
				new CodeBaseReferenceExpression(), "InnerList"), 
				"Add", 
				new CodeExpression[] 
							{ new CodeArgumentReferenceExpression("value") } 
				)
				)
				);

			// Add to type
			col.Members.Add(add);

			// IndexOf method
			CodeMemberMethod indexOf = new CodeMemberMethod();
			indexOf.Attributes = MemberAttributes.Final | MemberAttributes.Public;
			indexOf.Name = "IndexOf";
			indexOf.ReturnType = new CodeTypeReference(typeof(int));
			indexOf.Parameters.Add( new CodeParameterDeclarationExpression (
				forType, "value" ) );

			if(nullchk != null) indexOf.Statements.Add(nullchk); // BDS: Add null check for the value parameter. 
			
			// Generates: return base.InnerList.IndexOf(value);
			indexOf.Statements.Add( new CodeMethodReturnStatement (
				new CodeMethodInvokeExpression( 
				new CodePropertyReferenceExpression( 
				new CodeBaseReferenceExpression(), "InnerList"), 
				"IndexOf", 
				new CodeExpression[] 
					{ new CodeArgumentReferenceExpression( "value" ) } 
				)
				)
				);

			// Add to type
			col.Members.Add(indexOf);

			/*
			public void Insert( int index, Int16 value )
			{
				List.Insert( index, value );
			}
			*/
			// Insert method
			CodeMemberMethod insert = new CodeMemberMethod();
			insert.Attributes = MemberAttributes.Final | MemberAttributes.Public;
			insert.Name = "Insert";
			insert.ReturnType = new CodeTypeReference(typeof(void));
			insert.Parameters.Add( new CodeParameterDeclarationExpression (
				typeof(int), "index" ) );
			insert.Parameters.Add( new CodeParameterDeclarationExpression (
				forType, "value" ) );

			if(nullchk != null) insert.Statements.Add(nullchk); // BDS: Add null check for the value parameter.
			
			// Generates: return base.InnerList.Insert(index, value);
			insert.Statements.Add( new CodeExpressionStatement (
				new CodeMethodInvokeExpression( 
				new CodePropertyReferenceExpression( 
				new CodeBaseReferenceExpression(), "InnerList"), 
				"Insert", 
				new CodeExpression[] 
					{
						new CodeArgumentReferenceExpression( "index" ),
						new CodeArgumentReferenceExpression( "value" ) } 
				)
				)
				);

			// Add to type
			col.Members.Add(insert);

			/*
			public void Remove( Int16 value )
			{
				List.Remove( value );
			}
			*/
			// Remove method
			CodeMemberMethod remove = new CodeMemberMethod();
			remove.Attributes = MemberAttributes.Final | MemberAttributes.Public;
			remove.Name = "Remove";
			remove.ReturnType = new CodeTypeReference(typeof(void));
			remove.Parameters.Add( new CodeParameterDeclarationExpression (
				forType, "value" ) );
				
			if(nullchk != null) remove.Statements.Add(nullchk); // BDS: Add null check for the value parameter.

			// Generates: return base.InnerList.Remove(value);
			remove.Statements.Add( new CodeExpressionStatement (
				new CodeMethodInvokeExpression( 
				new CodePropertyReferenceExpression( 
				new CodeBaseReferenceExpression(), "InnerList"), 
				"Remove", 
				new CodeExpression[] 
					{ new CodeArgumentReferenceExpression( "value" ) } 
				)
				)
				);

			// Add to type
			col.Members.Add(remove);

			/*
			public bool Contains( Int16 value )
			{
				// If value is not of type Int16, this will return false.
				return( List.Contains( value ) );
			}
			*/
			// Contains method
			CodeMemberMethod contains = new CodeMemberMethod();
			contains.Attributes = MemberAttributes.Final | MemberAttributes.Public;
			contains.Name = "Contains";
			contains.ReturnType = new CodeTypeReference(typeof(bool));
			contains.Parameters.Add( new CodeParameterDeclarationExpression (
				forType, "value" ) );

			if(nullchk != null) contains.Statements.Add(nullchk); // BDS: Add null check for the value parameter.
			
			// Generates: return base.InnerList.Contains(value);
			contains.Statements.Add( new CodeMethodReturnStatement (
				new CodeMethodInvokeExpression( 
				new CodePropertyReferenceExpression( 
				new CodeBaseReferenceExpression(), "InnerList"), 
				"Contains", 
				new CodeExpression[] 
					{ new CodeArgumentReferenceExpression( "value" ) } 
				)
				)
				);

			// Add to type
			col.Members.Add(contains);

			// Indexer property ('this')
			CodeMemberProperty indexer = new CodeMemberProperty();
			indexer.Attributes = MemberAttributes.Final | MemberAttributes.Public;
			indexer.Name = "Item";
			indexer.Type = forType;
			indexer.Parameters.Add( new CodeParameterDeclarationExpression (
				typeof( int ), "idx" ) );
			indexer.HasGet = true;
			indexer.HasSet = true;

			// Generates: return (theType) base.InnerList[idx];
			indexer.GetStatements.Add( 
				new CodeMethodReturnStatement (
				new CodeCastExpression( 
				forType, 
				new CodeIndexerExpression( 
				new CodePropertyReferenceExpression( 
				new CodeBaseReferenceExpression(), 
				"InnerList"), 
				new CodeExpression[] 
			{ new CodeArgumentReferenceExpression( "idx" ) } ) 
				)
				)
				);

			if(nullchk != null) indexer.SetStatements.Add(nullchk); // BDS: Add null check for the value parameter.
			
			// Generates: base.InnerList[idx] = value;
			indexer.SetStatements.Add( 
				new CodeAssignStatement( 
				new CodeIndexerExpression( 
				new CodePropertyReferenceExpression( 
				new CodeBaseReferenceExpression(), 
				"InnerList"), 
				new CodeExpression[] 
		  { new CodeArgumentReferenceExpression("idx") }), 
				new CodeArgumentReferenceExpression( "value" )
				)
				);

			// Add to type
			col.Members.Add(indexer);
			return col;
		}
		
		// 08-04-2005 BDS
		// We used an ArrayList to keep track of the generated collection types. However, this preveneted us
		// from being able to check for the generated collection types prior to generating it. 
		// Because of this when I changed the collection generation routine to generate a unique type name; 
		// this routine generated multiple collection types for the same entity type. Therefore I changed 
		// "typeNames" variable type to HashTable and used it to store the collection type correspoding to 
		// entity type. After that I checked whether the collection type is already generated, before generating
		// it.
		internal static void ChangeArraysToCollections(ref CodeNamespace code, bool asmx)
		{
			// Copy as we will be adding types
			CodeTypeDeclaration[] types = 
				new CodeTypeDeclaration[code.Types.Count];
			code.Types.CopyTo(types, 0);
			Hashtable typeNames = new Hashtable(); 
			string itemsChoiceType = "";
			string refItemsChoiceType = "";

			foreach(CodeTypeDeclaration type in types)
			{
				// BDS: Allowed to process if the type is an Interface.
				// Reason: This is to makesure that all the array type parameters and retrun values are
				// converted to collections.
				if(type.IsClass || type.IsStruct || type.IsInterface)
				{
                    // BDS: Avoid this conversion for the event args types.
                    if (type.BaseTypes.Count == 1 && 
                        type.BaseTypes[0].BaseType == "System.ComponentModel.AsyncCompletedEventArgs")
                    {
                        continue;
                    }

					foreach(CodeTypeMember member in type.Members)
					{
						// Process fields
						if (member is CodeMemberField && 
							((CodeMemberField)member).Type.BaseType != "System.Byte" && 
							((CodeMemberField)member).Type.ArrayElementType != null)
						{
							foreach (CodeAttributeDeclaration attr in ((CodeMemberField)member).CustomAttributes)
							{
								if (attr.Name == "System.Xml.Serialization.XmlChoiceIdentifierAttribute")
								{
									CodeAttributeArgumentCollection args = attr.Arguments;
									itemsChoiceType = ((CodePrimitiveExpression)args[0].Value).Value.ToString();
									refItemsChoiceType = member.Name;
								}
							}

							if((((CodeMemberField)member).Name != itemsChoiceType) &&
								(((CodeMemberField)member).Name != refItemsChoiceType))
							{
								CodeMemberField field = (CodeMemberField)member;
								if(typeNames.Contains(field.Type.ArrayElementType.BaseType))
								{							
									field.Type = 
										new CodeTypeReference(
										typeNames[field.Type.ArrayElementType.BaseType].ToString());
								}
								else
								{
									// BDS: Changed the function call to pass the CodeNamespace in code 
									// parameter to GetCollectionType function.
									CodeTypeDeclaration col = GetCollectionForType( 
										field.Type.ArrayElementType,code );							
									code.Types.Add(col);
									typeNames.Add(field.Type.ArrayElementType.BaseType, col.Name);
									field.Type = new CodeTypeReference(col.Name);																	
								}
							}
						}					
					}
				}
			}
		}

        internal static void ChangeArraysToGenericList(ref CodeNamespace code, bool asmx)
        {
            string itemsChoiceType = "";
            string refItemsChoiceType = "";

            foreach (CodeTypeDeclaration type in code.Types)
            {
                // BDS: Allowed to process if the type is an Interface.
                // Reason: This is to makesure that all the array type parameters and retrun values are
                // converted to collections.
                if (type.IsClass || type.IsStruct || type.IsInterface)
                {
                    // BDS: Avoid this conversion for the event args types.
                    if (type.BaseTypes.Count == 1 &&
                        type.BaseTypes[0].BaseType == "System.ComponentModel.AsyncCompletedEventArgs")
                    {
                        continue;
                    }

                    foreach (CodeTypeMember member in type.Members)
                    {
                        // Process fields
                        if (member is CodeMemberField &&
                            ((CodeMemberField)member).Type.BaseType != "System.Byte" &&
                            ((CodeMemberField)member).Type.ArrayElementType != null)
                        {
                            foreach (CodeAttributeDeclaration attr in ((CodeMemberField)member).CustomAttributes)
                            {
                                if (attr.Name == "System.Xml.Serialization.XmlChoiceIdentifierAttribute")
                                {
                                    CodeAttributeArgumentCollection args = attr.Arguments;
                                    itemsChoiceType = ((CodePrimitiveExpression)args[0].Value).Value.ToString();
                                    refItemsChoiceType = member.Name;
                                }
                            }

                            if ((((CodeMemberField)member).Name != itemsChoiceType) &&
                                (((CodeMemberField)member).Name != refItemsChoiceType))
                            {
                                CodeMemberField field = (CodeMemberField)member;
                                CodeTypeReference gtype = new CodeTypeReference(typeof(List<>));
                                gtype.TypeArguments.Add(new CodeTypeReference(field.Type.BaseType));
                                field.Type = gtype;    
                            }
                        }
                    }
                }
            }
        }

		internal static void EmitCodeComments(ServiceDescriptionImporter serviceDescriptionImporter, ref CodeNamespace codeNamespace)
		{
			Hashtable htMethodComments = new Hashtable();
			Hashtable htClassComments = new Hashtable();
			
			// BDS: 09-16-2005
			// Changed all the lower case conversions in the procedure. Lower case conversion may cause incorrect results 
			// because the C# language constructs are case sensitive. For example: a service can have two operations such 
			// as DoSomething and dosomething. 
			try
			{
				if (serviceDescriptionImporter.ServiceDescriptions.Count > 0)
				{
					foreach(ServiceDescription sDesc in serviceDescriptionImporter.ServiceDescriptions)
					{
						foreach(PortType svc in sDesc.PortTypes)
						{
							string serviceName = svc.Name.Replace("Interface", "");
							htClassComments.Add(serviceName, svc.Documentation);	
							
							if(sDesc.PortTypes.Count > 0)
							{
								if (sDesc.PortTypes[0].Operations.Count > 0)
								{
									foreach(Operation op in svc.Operations /*serviceDescriptionImporter.ServiceDescriptions[0].PortTypes[0].Operations*/)
									{
										htMethodComments.Add(serviceName + ":::" + op.Name, 
											op.Documentation);	
										// BDS: Added the following code to retrive the comments for the in/out messages.
										if(op.Messages.Input != null)
										{
											Message msgIn = 
												sDesc.Messages[op.Messages.Input.Message.Name];
											if(msgIn.Documentation != "")
											{
												htMethodComments.Add(
													serviceName + ":::" + op.Name + ":::In", 
													msgIn.Documentation);	
											}
										}
										if(op.Messages.Output != null)
										{
											Message msgOut = 
												sDesc.Messages[op.Messages.Output.Message.Name];
											if(msgOut.Documentation != "")
											{
												htMethodComments.Add(
													serviceName + ":::" + op.Name + ":::Out", 
													msgOut.Documentation);	
											}
										}
									}
								} // End of: if (sDesc.PortTypes[0].Operations.Count > 0)
							} // End of: if(sDesc.PortTypes.Count > 0)
						} // End of: foreach(PortType svc in sDesc.PortTypes)
						
						foreach(CodeTypeDeclaration decl in codeNamespace.Types)
						{
							string typeName = decl.Name;
							if(htClassComments.Contains(typeName))
							{
								string classComment = htClassComments[typeName].ToString();
								decl.Comments.Clear();							
								decl.Comments.AddRange(GetSummeryComment(classComment));
							}

							if(decl.BaseTypes.Count > 0)
							{
								// BDS: Modified this condition to add method level comments in the stub code file.
								if(decl.BaseTypes[0].BaseType == "System.Web.Services.WebService" ||
									decl.BaseTypes[0].BaseType == "System.Web.Services.Protocols.SoapHttpClientProtocol" ||
									decl.BaseTypes[0].BaseType == "Thinktecture.Tools.Web.Services.Extensions.SoapHttpClientProtocolExtended")
								{
									foreach(CodeTypeMember cmm in decl.Members)
									{
										if(cmm is CodeMemberMethod)
										{
											string methodComment = "";

											if(htMethodComments.Contains(
												typeName + ":::" + ((CodeMemberMethod)cmm).Name))
											{
												methodComment = 
													htMethodComments[typeName + ":::" + 
													((CodeMemberMethod)cmm).Name].ToString();
												((CodeMemberMethod)cmm).Comments.Clear();
												((CodeMemberMethod)cmm).Comments.AddRange(GetSummeryComment(methodComment));
											}	
											
											// BDS: Added the following code to emmit the documentation for parameter message and return message.
											if(htMethodComments.Contains(
												typeName + ":::" + 
												((CodeMemberMethod)cmm).Name + 
												":::In"))
											{
												methodComment = 
													htMethodComments[typeName + ":::" + 
													((CodeMemberMethod)cmm).Name + ":::In"].ToString();																	
												((CodeMemberMethod)cmm).Comments.Add(new CodeCommentStatement("<param name=\"\">" + methodComment + "</param>", true));
											}
		
											if(htMethodComments.Contains(
												typeName + ":::" + ((CodeMemberMethod)cmm).Name + ":::Out"))
											{
												methodComment = htMethodComments[typeName + ":::" + ((CodeMemberMethod)cmm).Name + ":::Out"].ToString();
												((CodeMemberMethod)cmm).Comments.Add(new CodeCommentStatement("<returns>" + methodComment + "</returns>", true));
											}
										}
									} // End of: foreach(CodeTypeMember cmm in decl.Members)
								} // End of: If condition
							} // End of: if(decl.BaseTypes.Count > 0)
						} // End of: foreach(CodeTypeDeclaration decl in codeNamespace.Types)
					} // End of: foreach(ServiceDescription sDesc in serviceDescriptionImporter.ServiceDescriptions)
				} // End of: if (serviceDescriptionImporter.ServiceDescriptions.Count > 0)
			} // End of: try
			catch(Exception)
			{
				throw;
			}
		}

        /// <summary>
        /// Converts the public fields to properties.
        /// </summary>
        internal static void ChangeFieldsToProperties(ref CodeNamespace cns, 
                                                        string language, 
                                                        bool enableDatabinding, 
                                                        CodeNamespace original, 
                                                        bool noXxxSpecifiedHandling
                                                    )
		{
			foreach (CodeTypeDeclaration codeType in cns.Types)
			{
				ArrayList codeFieldList = null;
				
				foreach (CodeTypeMember codeMember in codeType.Members)
				{
					CodeMemberField codeField = codeMember as CodeMemberField;

					if (codeField == null) // This member is not a field so move on.
						continue;

                    // Is this a public field? If 'Yes' add it to the processing list.
					if ((codeField.Attributes & MemberAttributes.Public) == MemberAttributes.Public)
					{
						if (codeFieldList == null)
							codeFieldList = new ArrayList(codeType.Members.Count);

						codeFieldList.Add(codeField);
					}
				}

				if (codeFieldList == null) // Move on if there are no public fields in this type.
					continue;
                
                // If databinding is enabled make sure this type or one of its parents in the inheritance hierarcy
                // implements the INotifyPropertyChanged interface.
                bool isINotifyPropertyChanged = false;
                if(enableDatabinding)
                    isINotifyPropertyChanged = Implements(cns, codeType, "System.ComponentModel.INotifyPropertyChanged"); 
               
                // Enable backtracking. Keep track of the last property name and the set statements collection 
                // generated by the itteration.
                string lastItem = null;
                CodeStatementCollection lastSetStatements = null;

				for (int index = 0; index < codeFieldList.Count; index++)
				{
                    CodeMemberField codeField = (CodeMemberField)codeFieldList[index];
					CodeMemberProperty codeProperty = new CodeMemberProperty();
					codeProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final;

                    // Clone the attributes in the public field to the newly created property.
					codeProperty.CustomAttributes.AddRange(codeField.CustomAttributes); 

					// BDS: Use the pascal case convention for the properties, only if naming conventions are 
					// applicable.
					if(namingConventionsApplicable)
					{
						// BDS: Make the public property name to use Pascal casing.					
						codeProperty.Name = codeField.Name.Substring(0, 1).ToUpper(CultureInfo.CurrentCulture);
						if(codeField.Name.Length > 1)
						{
							codeProperty.Name += codeField.Name.Substring(1);
						}

						// BDS: Make the private field to use Camel casing.
						codeField.Name = codeProperty.Name.Substring(0, 1).ToLower(CultureInfo.CurrentCulture);
						if (codeProperty.Name.Length > 1)
						{
							codeField.Name += codeProperty.Name.Substring(1);
						}

						// BDS: Fixed a bug here. VB code is case insensitive. Therefore added an under bar
						// infront of the private member name.
						if(language.ToLower() == "vb")
						{
							codeField.Name = "_" + codeField.Name;
						}
					}
					else
					{
						codeProperty.Name = codeField.Name;
						codeField.Name = string.Format(CultureInfo.CurrentCulture, "_{0}", codeField.Name);
					}
					
					
					// BDS: Check wheter the null checks are applicable.  
					// Reason: .Net does not allow null values for value data types.	
                    bool isValueType = false;

                    if (original == null)
                    {
                        isValueType = IsValueType(codeField.Type.BaseType, cns);
                    }
                    else
                    {
                        isValueType = IsValueType(codeField.Type.BaseType, original);
                    }

                    if(!isValueType)
					{
                        // BDS: 01/18/2006
                        // Do not generate the null check in the property setter for nullable fields.
                        // nullable fields: Represents the elements whose nillable attribute is set to true.
                        bool isNullable = false;
                        CodeAttributeArgument nullableAttribute = HasAttributeArgument(
                            @"System.Xml.Serialization.XmlElementAttribute", @"IsNullable", 
                            codeField.CustomAttributes);

                        if(nullableAttribute == null)
                        {
                            nullableAttribute = HasAttributeArgument(
                            @"System.Xml.Serialization.SoapElementAttribute", @"IsNullable",
                            codeField.CustomAttributes);      	
                        }

                        if (nullableAttribute != null)
                        {
                            CodePrimitiveExpression val = nullableAttribute.Value as CodePrimitiveExpression;
                            if (val != null)
                            {
                                if (val.Value.GetType() == typeof(bool))
                                {
                                    isNullable = (bool)val.Value;
                                }
                            }
                        }

						// Create the condition for the get-ter.
						CodeConditionStatement getnullchk = new CodeConditionStatement();
						CodeBinaryOperatorExpression gcondition = 
							new CodeBinaryOperatorExpression(new CodeFieldReferenceExpression(
							new CodeThisReferenceExpression(),codeField.Name),
							CodeBinaryOperatorType.IdentityEquality, 
							new CodePrimitiveExpression(null));
						getnullchk.Condition = gcondition;

                        if (!isNullable)
                        {
                            // Create the condition for the set-ter.
                            CodeConditionStatement setnullchk = new CodeConditionStatement();
                            CodeBinaryOperatorExpression scondition =
                                new CodeBinaryOperatorExpression(new CodePropertySetValueReferenceExpression(),
                                CodeBinaryOperatorType.IdentityEquality,
                                new CodePrimitiveExpression(null));
                            setnullchk.Condition = scondition;

                            // Create the throw exception statment.
                            CodeThrowExceptionStatement throwException = new CodeThrowExceptionStatement(
                                new CodeObjectCreateExpression(
                                new CodeTypeReference(typeof(ArgumentNullException)),
                                new CodePrimitiveExpression[1] { new CodePrimitiveExpression(codeProperty.Name) }));
                            setnullchk.TrueStatements.Add(throwException);

                            codeProperty.SetStatements.Add(setnullchk);
                        }
   					}

                    CodeStatementCollection stmts = null;

                    // BDS: Also added another condition for VB code generation.
                    // We currently do not generate this condtion for reference types, 
                    // reference type/value type arrays and generic types.
                    if ((language.ToLower() == "cs") || 
                        (language.ToLower() == "vb" && isValueType && 
                        codeField.Type.ArrayElementType == null && 
                        codeField.Type.TypeArguments.Count == 0))
                    {
                        // if(this.Xyz != value)
                        CodeConditionStatement newValue = new CodeConditionStatement();
                        newValue.Condition = new CodeBinaryOperatorExpression(new CodeFieldReferenceExpression(
                                new CodeThisReferenceExpression(), codeField.Name),
                                CodeBinaryOperatorType.IdentityInequality,
                                new CodePropertySetValueReferenceExpression());

                        stmts = newValue.TrueStatements;
                        codeProperty.SetStatements.Add(newValue);
                    }
                    else
                    {
                        stmts = codeProperty.SetStatements;
                    }

                    // this.Xyz = value;
                    CodeAssignStatement assign = new CodeAssignStatement(new CodeFieldReferenceExpression(
                            new CodeThisReferenceExpression(), codeField.Name),
                            new CodeVariableReferenceExpression("value"));

                    stmts.Add(assign);

                    if (enableDatabinding && isINotifyPropertyChanged)
                    {
                        //RaisePropertyChanged("Xyz");
                        CodeMethodInvokeExpression raiseEvent = new CodeMethodInvokeExpression(
                            new CodeMethodReferenceExpression(new CodeThisReferenceExpression(),
                            "RaisePropertyChanged"), new CodePrimitiveExpression(codeProperty.Name));
                        stmts.Add(raiseEvent);                        

                    }
                   
					//
					// BDS: End of null check code snippet.
					//					                        

					codeProperty.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), codeField.Name)));                    
					codeProperty.Type = codeField.Type;
					codeField.Attributes = MemberAttributes.Private;
					codeField.CustomAttributes.Clear();
					ArrayList codeFieldAttrList = new ArrayList(codeField.CustomAttributes.Count);

					foreach (CodeAttributeDeclaration ca in codeField.CustomAttributes)
					{
						codeFieldAttrList.Add(ca);
					}

					foreach (CodeAttributeDeclaration ca in codeFieldAttrList)
					{
						codeField.CustomAttributes.Remove(ca);
						codeProperty.CustomAttributes.Add(ca);
					}

					codeType.Members.Add(codeProperty);


                    // Automatically enable the "xxxSpecified" field.                    
                    if (!noXxxSpecifiedHandling)
                    {
                        if (codeProperty.Name == lastItem + "Specified")
                        {
                            if (codeProperty.CustomAttributes.Count == 1 &&
                                codeProperty.CustomAttributes[0].AttributeType.BaseType == "System.Xml.Serialization.XmlIgnoreAttribute")
                            {
                                CodeFieldReferenceExpression fref = new CodeFieldReferenceExpression(
                                    new CodeThisReferenceExpression(), codeField.Name);
                                CodeAssignStatement set = new CodeAssignStatement(fref, new CodePrimitiveExpression(true));
                                lastSetStatements.Add(set);
                            }
                        }

                        // Set this item values to backtracking variables.
                        lastItem = codeProperty.Name;
                        lastSetStatements = stmts;
                    }

                } // foreach (CodeMemberField codeField in codeFieldList)

				CodeAttributeDeclaration cad = new CodeAttributeDeclaration(
					"System.ComponentModel.TypeConverterAttribute", new CodeAttributeArgument(new CodeTypeOfExpression("System.ComponentModel.ExpandableObjectConverter")));
				codeType.CustomAttributes.Add(cad);
			}
		}

		internal static void RemoveSerializableAttribute(ref CodeNamespace cns)
		{
			foreach (CodeTypeDeclaration codeType in cns.Types)
			{
				// BDS: Added a condtion to check whether the type declaration is an interface or not.
				// Reason: It is illigal to have Serializable attribute for interfaces.
				if(!codeType.IsInterface)
				{
					if(codeType.BaseTypes.Count > 0)
					{
						if(codeType.BaseTypes[0].BaseType == "System.Web.Services.WebService" &&
							codeType.BaseTypes[0].BaseType == "System.Web.Services.Protocols.SoapHttpClientProtocol" &&
							codeType.BaseTypes[0].BaseType == "Thinktecture.Tools.Web.Services.Extensions.SoapHttpClientProtocolExtended")
						{
                            continue;
						}
					}

                    int aindex = 0;
                    while(aindex < codeType.CustomAttributes.Count)
                    {
                        CodeAttributeDeclaration currentAttribute = codeType.CustomAttributes[aindex];

                        if (currentAttribute.Name == @"System.SerializableAttribute")
                        {
                            codeType.CustomAttributes.Remove(currentAttribute);
                        }
                        else
                        {
                            aindex++;
                        }
                    }
				}
			}
		}
		
		
		/// <summary>
		/// This method adds constructors for all the classes found in a given namespace. 
		/// </summary>
		/// <param name="cns">CodeDOM Namespace containing the type declarations.</param>
		/// <author>BDS - thinktecture</author>
		/// <todo>
		/// Take care of the initialization of the types with parameterized constructors.
		/// </todo>
		internal static void AddCtors(CodeNamespace cns)
		{
			foreach(CodeTypeDeclaration type in cns.Types)
			{
				if(type.IsClass)
				{
					// Ignore if the ctor is already there.
					bool ctorfound = false;
					foreach(CodeTypeMember mem in type.Members)
					{
						if(mem is CodeConstructor)
						{
							ctorfound = true;
							break;
						}

					}					
					if(ctorfound) continue;

					CodeConstructor ctor = new CodeConstructor();		// Default ctor.
					CodeConstructor paramctor = new CodeConstructor();  // Parameterized ctor.

					ctor.Attributes = MemberAttributes.Public;
					paramctor.Attributes = MemberAttributes.Public;
					
					bool addparamctor = false; // Add param ctor only if members are found inside the type.

					// Add the field init statements.
					foreach(CodeTypeMember mem in type.Members)
					{
						CodeMemberField field = null;
						if(mem is CodeMemberField)
							field = (CodeMemberField)mem;
						else
							continue;
						
						//
						// Add a prameter to the param ctor.
						//
						// Create the parameter name.
						// Modified the code to remove the preceding 'p' from the paramer names.
						string pname = "";				
						pname = field.Name.Substring(0, 1).ToLower();
						if(field.Name.Length > 1)
						{
							pname += field.Name.Substring(1);
						}
						
						// Create the parameter.
						CodeParameterDeclarationExpression param = 
							new CodeParameterDeclarationExpression();						
						param.Name = pname;
						param.Type = field.Type;
						paramctor.Parameters.Add(param);

						// Add the parameter to field assignment statment.
						CodeAssignStatement paramtofield = new CodeAssignStatement(
							new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
							field.Name),new CodeArgumentReferenceExpression(param.Name));
						paramctor.Statements.Add(paramtofield);

						addparamctor = true;
					}
					
					// Finally add the ctors to the class.
					type.Members.Add(ctor); 
					if(addparamctor) type.Members.Add(paramctor);
				}
			}
		}

		/// <summary>
		/// This method extracts the documentation in the WSDL for each type. And it applies the 
		/// documentation to the source code generated. 
		/// </summary>
		/// <param name="pcns">CodeDOM namespace which contains the type declarations.</param>
		/// <param name="psdi">ServiceDescriptionImporter which contains the schema definitions from WSDL.</param>
		/// <author>BDS - thinktecture</author>
		internal static void ImportDocumentation(CodeNamespace pcns, ServiceDescriptionImporter psdi)
		{
			// Placeholder for the documentaion elements found in the WSDL.
			Hashtable documentationmap = new Hashtable();	
			
			//
			// Traverse the schemas found in the service description importer.
			//
			foreach(XmlSchema xs in psdi.Schemas)		
			{
				AddToDocumentationMap(documentationmap, xs);
			}
			
			//
			// Traverse the service descriptions found in the service description importer.
			// Reason: Sometimes the type definitions could be within the WSDL itself without 
			// imported XSDs.
			//
			foreach(ServiceDescription sd in psdi.ServiceDescriptions)
			{
				foreach(XmlSchema xs in sd.Types.Schemas)
				{
					AddToDocumentationMap(documentationmap,xs);
				}
			}

			// Navigate through the CodeNamespace and add the comments.
			string key = string.Empty;
			foreach(CodeTypeDeclaration type in pcns.Types)
			{
				// Obtain the type's XML namespace.
				string typexmlns = string.Empty;
				foreach(CodeAttributeDeclaration attribdcl in type.CustomAttributes)
				{
					if(attribdcl.Name == "System.Web.Services.WebServiceAttribute" ||
						attribdcl.Name == "System.Xml.Serialization.XmlTypeAttribute")
					{
						foreach(CodeAttributeArgument attribarg in attribdcl.Arguments)
						{
							if(attribarg.Name == "Namespace")
							{
								typexmlns = ((CodePrimitiveExpression)attribarg.Value).Value.ToString();
							}
						}
					}
				}
				
				string fqtypename = typexmlns + "." + type.Name; // Fully qulified name of the type.
				// Insert the documentation for the type, if any.
				if(documentationmap.Contains(fqtypename))
				{
					type.Comments.Clear();
					type.Comments.AddRange(GetSummeryComment(documentationmap[fqtypename].ToString()));
				}

				// Search for the documentation for the type's members.
				foreach(CodeTypeMember mem in type.Members)
				{					
					if(mem is CodeMemberField) // Look for the member fields.
					{
						CodeMemberField field = (CodeMemberField)mem;
						if((field.Attributes & MemberAttributes.Public) == MemberAttributes.Public)
						{
							// Insert the documentation for the type field, if any.
							key = fqtypename + "." + field.Name;
							if(documentationmap.Contains(key))	// Add the comments for the type.
							{
								field.Comments.Clear();
								field.Comments.AddRange(GetSummeryComment(documentationmap[key].ToString()));
							}
						}
					}
					else if(mem is CodeMemberProperty) // Look for the properties.
					{
						CodeMemberProperty field = (CodeMemberProperty)mem;
						if((field.Attributes & MemberAttributes.Public) == MemberAttributes.Public)
						{
							key =fqtypename + "." + field.Name;
							if(documentationmap.Contains(key)) // Add the comments for the type member.
							{
								field.Comments.Clear();
								field.Comments.AddRange(GetSummeryComment(documentationmap[key].ToString()));
							}
						}
					}
					else
						continue;
					
				}
			}
		}

		/// <summary>
		/// This helper method is used to create a comment inside the "summary" tags.
		/// </summary>
		/// <param name="pcontent">Content that suppose to appear inside the remarks.</param>
		/// <returns>CodeCommentStatementCollection with the prepared comment.</returns>
		/// <author>BDS - thinktecture</author>
		private static CodeCommentStatementCollection GetSummeryComment(string pcontent)
		{
			Debug.Assert(pcontent != null,"pcontent parameter could not be a null value");
			CodeCommentStatementCollection comments = new CodeCommentStatementCollection();
			comments.Add(new CodeCommentStatement("<summary>",true));
			comments.Add(new CodeCommentStatement(pcontent,true));
			comments.Add(new CodeCommentStatement("</summary>",true));
			
			return comments;
		}
		
		private static void AppendOrAddStringToHashtable(Hashtable target, string key, string value)
		{
			// Ensure the multiple documentation items are delimited by a period.
			if(!value.EndsWith("."))
			{
				value += ".";
			}

			if(target.Contains(key))
			{
				target[key] = string.Format("{0} {1}", target[key].ToString(), value); 
			}
			else
			{
				target.Add(key, value);
			}
		}
		/// <summary>
		/// This helper method is used to extract the documentation elements from a given schema
		/// and put them inside a hashtable.
		/// </summary>
		/// <param name="pdocmap">A reference to the HashTable to be filled.</param>
		/// <param name="pxs">XmlSchema object which contains the Xml schema.</param>
		private static void AddToDocumentationMap(Hashtable pdocmap, XmlSchema pxs)
		{            
			foreach(XmlSchemaObject xsobj in pxs.Items)
			{                
				if((xsobj is XmlSchemaComplexType)) // Proceed if the item is a ComplexType.
				{
					XmlSchemaComplexType xsct = (XmlSchemaComplexType)xsobj;
					if(xsct.Annotation != null)
					{
						foreach(XmlSchemaObject annotation in xsct.Annotation.Items)
						{
							if(annotation is XmlSchemaDocumentation)
							{
								XmlSchemaDocumentation doc = (XmlSchemaDocumentation)annotation;								
								AppendOrAddStringToHashtable(pdocmap, pxs.TargetNamespace + "." + xsct.Name, 
									GetStringFromXmlNodes(doc.Markup));								
							}
						}
					}
					
					// Traverse the child elments of ComplexType.
					if(xsct.Particle is XmlSchemaSequence) 
					{
						XmlSchemaSequence xsseq = (XmlSchemaSequence)xsct.Particle;
						
						foreach(XmlSchemaParticle xsmem in xsseq.Items)
						{
							if(xsmem is XmlSchemaElement)
							{
								XmlSchemaElement xselement = (XmlSchemaElement)xsmem;
								
								if(xselement.Annotation != null)
								{
									foreach(XmlSchemaObject annotation in xselement.Annotation.Items)
									{
										if(annotation is XmlSchemaDocumentation)
										{
											XmlSchemaDocumentation doc = (XmlSchemaDocumentation)annotation;
											AppendOrAddStringToHashtable(pdocmap, 
												pxs.TargetNamespace + "." + xsct.Name + "." + xselement.Name, 
												GetStringFromXmlNodes(doc.Markup));																			
										}
									}
								}
							}
						}
					}
				}
				else if(xsobj is XmlSchemaElement) // Proceed if the item is an element.
				{
					XmlSchemaElement xsele = (XmlSchemaElement)xsobj;
					
					// Record the documentation for the element if any.
					if(xsele.Annotation != null)
					{
						foreach(XmlSchemaObject annotation in xsele.Annotation.Items)
						{
							if(annotation is XmlSchemaDocumentation)
							{
								XmlSchemaDocumentation doc = (XmlSchemaDocumentation)annotation;
								AppendOrAddStringToHashtable(pdocmap, 
									pxs.TargetNamespace + "." + xsele.Name, 
									GetStringFromXmlNodes(doc.Markup));								
							}
						}
					}

					// Traverse the element items to find the documentation.
					if(xsele.SchemaType is XmlSchemaComplexType)
					{
						XmlSchemaComplexType xsct = (XmlSchemaComplexType)xsele.SchemaType;

						// Traverse the child elments of ComplexType.
						if(xsct.Particle is XmlSchemaSequence) 
						{
							XmlSchemaSequence xsseq = (XmlSchemaSequence)xsct.Particle;
						
							foreach(XmlSchemaParticle xsmem in xsseq.Items)
							{
								if(xsmem is XmlSchemaElement)
								{
									XmlSchemaElement childele = (XmlSchemaElement)xsmem;
								
									if(childele.Annotation != null)
									{
										foreach(XmlSchemaObject annotation in childele.Annotation.Items)
										{
											if(annotation is XmlSchemaDocumentation)
											{
												XmlSchemaDocumentation doc = (XmlSchemaDocumentation)annotation;
												AppendOrAddStringToHashtable(pdocmap, 
													pxs.TargetNamespace + "." + xsele.Name + "." + childele.Name, 
													GetStringFromXmlNodes(doc.Markup));													
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}

		internal static void RenameProxyStubCode(CodeNamespace cns)
		{
			foreach(CodeTypeDeclaration typeDcl in cns.Types)
			{		
				if((typeDcl.BaseTypes.Count > 0) &&
					(typeDcl.BaseTypes[0].BaseType == "System.Web.Services.WebService"))
				{
					// Check for the "Service" or "WebService" part in the type name and remove it.
					if(typeDcl.Name.ToLower() != "webservice" && typeDcl.Name.ToLower().EndsWith("webservice"))
					{
						typeDcl.Name = typeDcl.Name.Substring(0,typeDcl.Name.Length - 10);
						continue;
					}
					else if(typeDcl.Name.ToLower() != "service" && typeDcl.Name.ToLower().EndsWith("service"))
					{
						typeDcl.Name = typeDcl.Name.Substring(0,typeDcl.Name.Length - 7);
						continue;
					}					
					
				}
				else if((typeDcl.BaseTypes.Count > 0) && 
					((typeDcl.BaseTypes[0].BaseType == "System.Web.Services.Protocols.SoapHttpClientProtocol")
					|| (typeDcl.BaseTypes[0].BaseType == "Thinktecture.Tools.Web.Services.Extensions.SoapHttpClientProtocolExtended")))
				{	
					// Check for the "Service" or "WebService" part in the type name and remove it.
					if(typeDcl.Name.ToLower() != "webservice" && typeDcl.Name.ToLower().EndsWith("webservice"))
					{
						typeDcl.Name = typeDcl.Name.Substring(0,typeDcl.Name.Length - 10);
						continue;
					}
					else if(typeDcl.Name.ToLower() != "service" && typeDcl.Name.ToLower().EndsWith("service"))
					{
						typeDcl.Name = typeDcl.Name.Substring(0,typeDcl.Name.Length - 7);
						continue;
					}
					
				}
			}
		}

		private static void GenerateArrayWrappers(ref string wrapperName, ref string memberName, 
			ref string wrapperNamespace, CodeAttributeDeclarationCollection attributes, 
			CodeTypeDeclarationCollection generatedWrappers, string memberType)
		{			
			// Remove the array attributes using a LIFO based stack 
			// algorithm. 
			int nextItem = 0;
			CodeAttributeDeclarationCollection elementsCollection = 
				new CodeAttributeDeclarationCollection();

			while(attributes.Count > nextItem)
			{
				CodeAttributeDeclaration attribute = attributes[0];

				if(attribute.Name == "System.Xml.Serialization.XmlArrayItemAttribute")
				{
					CodeAttributeDeclaration xmlElement = 
						new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute");

					foreach(CodeAttributeArgument arg in attribute.Arguments)
					{
						if(arg.Name == "Namespace")
						{
							xmlElement.Arguments.Add(arg);
							continue;
						}

						if(arg.Name == "" || arg.Name == "ElementName")
						{
							CodePrimitiveExpression argValue = arg.Value as CodePrimitiveExpression;
							if(argValue != null && argValue.Value is string)
							{
								memberName = argValue.Value.ToString();
								xmlElement.Arguments.Add(arg);
							}
							continue;
						}

						if(arg.Name == "Form")
						{
							xmlElement.Arguments.Add(arg);
							continue;
						}

						if(arg.Name == "DataType")
						{
							xmlElement.Arguments.Add(arg);
							continue;
						}

						if(arg.Name == "IsNullable" )
						{
							xmlElement.Arguments.Add(arg);
							continue;
						}
					}
					elementsCollection.Add(xmlElement);							
					attributes.Remove(attribute);
				}
				else if(attribute.Name == "System.Xml.Serialization.XmlArrayAttribute")
				{									
					foreach(CodeAttributeArgument arg in attribute.Arguments)
					{
						if(arg.Name == "Namespace")
						{
							CodePrimitiveExpression argValue = arg.Value as CodePrimitiveExpression;
							wrapperNamespace = argValue.Value.ToString();
														
							continue;
						}

						if(arg.Name == "" || arg.Name == "ElementName")
						{
							CodePrimitiveExpression argValue = arg.Value as CodePrimitiveExpression;
							if(argValue != null && argValue.Value is string)
							{
								wrapperName = argValue.Value.ToString();
							}

							continue;
						}
					}

					// Remove the array type attribute.
					attributes.Remove(attribute);
				}
				else
				{
					nextItem++; 
				}											
			}																									
										
			// Generate and add the wrapper if it is not there already.
			bool wrapperExists = false;
			foreach(CodeTypeDeclaration aw in generatedWrappers)
			{
				if(aw.Name == wrapperName)
				{
					wrapperExists = true;
					break;
				}
			}
										
			if(!wrapperExists)
			{
				CodeTypeDeclaration wrapper = GenerateArrayWrapper(wrapperName, wrapperNamespace,
					memberName, memberType, elementsCollection );
									
				generatedWrappers.Add(wrapper);										
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="cns"></param>
		internal static void GenerateArrayWrappers(CodeNamespace cns, ServiceDescriptionImporter sdi)
		{
			// Validate the parameters. 
			Debug.Assert((cns != null), "Parameter cns could not be null");
			
			if(!WrapArrayParameters(sdi))
			{
				return;
			}
	
			CodeTypeDeclarationCollection generatedWrappers = new CodeTypeDeclarationCollection();
			Hashtable wrapperToMethod = new Hashtable();

			foreach(CodeTypeDeclaration codeType in cns.Types)
			{
				if(codeType.BaseTypes.Count > 0)
				{
					if(codeType.BaseTypes[0].BaseType == "System.Web.Services.WebService" ||
						codeType.BaseTypes[0].BaseType == "System.Web.Services.Protocols.SoapHttpClientProtocol" ||
						codeType.BaseTypes[0].BaseType == "Thinktecture.Tools.Web.Services.Extensions.SoapHttpClientProtocolExtended")
					{
						foreach(CodeTypeMember member in codeType.Members)
						{
							if(member is CodeMemberMethod)
							{													
								CodeMemberMethod method = member as CodeMemberMethod;								

								// BDS: Added this gate to check whether the current method is using wrpped style
								// SOAP parameters.
								if(IsDocLitWrapped(method))
								{
									continue;
								}

								// Check whether the current member is an async begin member.
								// Modify the async begin method. 
								if(((CodeMemberMethod)member).ReturnType.BaseType == "System.IAsyncResult")
								{
                                    string mname = method.Name.Substring(5);
                                    mname += "In";
									
                                    if(wrapperToMethod[mname] != null)
									{
										method.Parameters[0].Type = 
											new CodeTypeReference(wrapperToMethod[mname].ToString());                                        
									}											
                                    
									continue;
								}

                                // Check whether the current member is a new async member.
                                if (method.Name.EndsWith("Async"))
                                {
                                    string mname = method.Name.Substring(0, method.Name.Length - 5);
                                    mname += "In";

                                    if (wrapperToMethod[mname] != null)
                                    {
                                        method.Parameters[0].Type =
                                            new CodeTypeReference(wrapperToMethod[mname].ToString());
                                    }

                                    continue;
                                }
                                
								// Check whether the member is a async end member.
								if(method.Parameters.Count > 0)
								{
									if(method.Name.StartsWith("End") && 
										method.Parameters[0].Type.BaseType == "System.IAsyncResult")
									{
										string mname = method.Name.Substring(3) + "Out";
										if(wrapperToMethod[mname] != null)
										{
											if(method.ReturnType.ArrayElementType != null)
											{
												// Change the return type.
												method.ReturnType.ArrayElementType = null;
												method.ReturnType = 
													new CodeTypeReference(wrapperToMethod[mname].ToString());
												
												// Change the return statement.
												foreach(CodeStatement statement in method.Statements)
												{
													CodeMethodReturnStatement ret = 
														statement as CodeMethodReturnStatement;

													if(ret != null)
													{
														CodeCastExpression cast = 
															ret.Expression as CodeCastExpression;													
														cast.TargetType = method.ReturnType;
													}
												}
											}	
											
											// Change the out parameter if there is one.
											if(method.Parameters.Count == 2 && 
												method.Parameters[0].Direction == FieldDirection.Out)
											{
												method.Parameters[1].Type = 
													new CodeTypeReference(wrapperToMethod[mname].ToString());
												
												// Change the assign statement.
												foreach(CodeStatement statement in method.Statements)
												{
													CodeAssignStatement assign = 
														statement as CodeAssignStatement;

													if(assign != null)
													{
														CodeCastExpression cast = 
															assign.Right as CodeCastExpression;													
														cast.TargetType = new CodeTypeReference(wrapperToMethod[mname].ToString());
													}
												}
											}
										}

										continue;
									}
								}

								// Check parameters								
								foreach(CodeParameterDeclarationExpression param in method.Parameters)
								{																																				
									if(param.Type.ArrayElementType != null && param.Type.BaseType != "System.Byte")
									{
										
										// Do not generate the wrapper if the parameter type is a jagged array.
										if(IsJaggedArray(param.CustomAttributes))
										{
											continue;
										}

										string wrapperName = param.Name;
										string memberName = param.Type.ArrayElementType.BaseType;
										string wrapperNamespace = "";									
										
										// Call the private helper function to generate the wrapper.
										GenerateArrayWrappers(ref wrapperName, ref memberName, 
											ref wrapperNamespace, 											
											param.CustomAttributes, 
											generatedWrappers, 
											param.Type.ArrayElementType.BaseType);

										// Add a new XmlElementAttribute to the parameter.
										CodeAttributeDeclaration elementAttribute = new CodeAttributeDeclaration
											("System.Xml.Serialization.XmlElementAttribute", 
											new CodeAttributeArgument(new CodePrimitiveExpression(wrapperName)), 
											new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(wrapperNamespace)));
																
										param.CustomAttributes.Add(elementAttribute);
										
										// Change param type to collection
										param.Type = new CodeTypeReference(wrapperName);
										wrapperToMethod.Add(method.Name + "In", wrapperName);
										
										// Change the assignment statment for the ref parameters.
										if(param.Direction == FieldDirection.Ref)
										{
											foreach(CodeStatement statement in method.Statements)
											{
												CodeAssignStatement assign = 
													statement as CodeAssignStatement;
												if(assign != null)
												{
													CodeCastExpression cast = 
														assign.Right as CodeCastExpression;
													if(cast != null)
													{
														cast.TargetType = param.Type;
													}
												}
											}
											// BDS: Add the same wrapper for the output message.
											wrapperToMethod.Add(method.Name + "Out", wrapperName);
										}

										// Break the loop because there could be only one parameter.
										break;
									}
								}
							
								// Check the return types.
								if(method.ReturnType.ArrayElementType != null && 
									method.ReturnType.BaseType != "System.Byte")
								{
									// Do not generate the wrapper if the return type is a jagged array.
									if(IsJaggedArray(method.ReturnTypeCustomAttributes))
									{
										continue;
									}

									string wrapperName = "";
									string memberName = method.ReturnType.ArrayElementType.BaseType;
									string wrapperNamespace = "";									
										
									// Call the private helper function to generate the wrapper.
									GenerateArrayWrappers(ref wrapperName, ref memberName, 
										ref wrapperNamespace, 										
										method.ReturnTypeCustomAttributes, 
										generatedWrappers,
										method.ReturnType.ArrayElementType.BaseType);
							
									// Add a new XmlElementAttribute to the return type attributes collection.
									CodeAttributeDeclaration elementAttribute = new CodeAttributeDeclaration
										("System.Xml.Serialization.XmlElementAttribute", 
										new CodeAttributeArgument(new CodePrimitiveExpression(wrapperName)), 
										new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(wrapperNamespace)));
									method.ReturnTypeCustomAttributes.Add(elementAttribute);

									// Change param type to collection
									method.ReturnType = new CodeTypeReference(wrapperName);
									method.ReturnType.ArrayElementType = null;
									
									// Change the return statement.
									foreach(CodeStatement statement in method.Statements)
									{
										CodeMethodReturnStatement ret = statement as CodeMethodReturnStatement;
										
										if(ret != null)
										{
											CodeCastExpression cast = ret.Expression as CodeCastExpression;
											cast.TargetType = method.ReturnType;
											break;
										}
									}

									wrapperToMethod.Add(method.Name + "Out", wrapperName);
								}
							}
						}
					} // Service/Proxy type check.
                    else if (codeType.BaseTypes[0].BaseType == "System.ComponentModel.AsyncCompletedEventArgs")
                    {
                        // Change the type in the evet args property.
                        if(codeType.Name.Length > 18)
                        {
                            string mname = codeType.Name.Substring(0, codeType.Name.Length - 18);
                            mname += "Out";

                            if(wrapperToMethod[mname] != null)
                            {
                                foreach (CodeTypeMember member in codeType.Members)
                                {
                                    if (member is CodeMemberProperty)
                                    {
                                        CodeMemberProperty prop = (CodeMemberProperty)member;
                                        prop.Type.ArrayElementType = null;

                                        CodeTypeReference returnType = new CodeTypeReference(wrapperToMethod[mname].ToString());
                                        prop.Type = returnType;

                                        foreach (CodeStatement statement in prop.GetStatements)
                                        {
                                            if (statement is CodeMethodReturnStatement)
                                            {
                                                CodeMethodReturnStatement ret = statement as CodeMethodReturnStatement;
                                                CodeCastExpression cast = ret.Expression as CodeCastExpression;

                                                if (cast != null)
                                                {
                                                    cast.TargetType = returnType;
                                                }

                                                break;
                                            }
                                        }

                                        break;
                                    } // if (member is CodeMemberProperty)
                                } // foreach (CodeTypeMember member in codeType.Members)
                            }  // if(wrapperToMethod[mname] != null)
                        } // if(codeType.Name.Length > 18)
                    }
				}
			}
			
			// Finally add all the generated wrappers to the Code DOM namespace.
			cns.Types.AddRange(generatedWrappers);
		}

        private class CallbackField
        {
            public CallbackField(CodeMemberField field, 
                CodeFieldReferenceExpression fieldReference, 
                CodeFieldReferenceExpression fieldReference2)
            {
                Field = field;
                FieldReference = fieldReference;
                FieldReference2 = fieldReference2;
            }

            public CallbackField(CodeMemberField field) : this(field, null, null)
            {
            }

            public CodeMemberField Field;
            public CodeFieldReferenceExpression FieldReference;
            public CodeFieldReferenceExpression FieldReference2;
        }

        private class EventMember
        {
            public EventMember(CodeMemberEvent eventDeclaration) : 
                this(eventDeclaration, null, null)
            {
            }

            public EventMember(CodeMemberEvent eventDeclaration,
                CodeEventReferenceExpression eventReference, 
                CodeEventReferenceExpression eventInvoke)
            {
                EventDeclaration = eventDeclaration;
                EventReference = eventReference;
                EventInvoke = eventInvoke;
            }

            public CodeMemberEvent EventDeclaration;
            public CodeEventReferenceExpression EventReference;
            public CodeEventReferenceExpression EventInvoke;
        }

		/// <summary>
		/// Converts the naming of .Net classes to pascal case.
		/// </summary>
		/// <param name="cns">CodeDOM namespace which contains the types for the conversion.</param>
		internal static void UsePascalCase(CodeNamespace cns)
		{
			int typeIndex = -1;

            // Keeps track of the custom EventArg type references that needs to be changed
            // when the event argument type name changes.
            Hashtable eventArgsMap = new Hashtable();
            ArrayList convertibleDelegates = new ArrayList();

			foreach(CodeTypeDeclaration type in cns.Types)
			{
                // Skip if this is an EventArg type which is not modified within the method level.
                if (type.BaseTypes.Count == 1 &&
                    type.BaseTypes[0].BaseType == "System.ComponentModel.AsyncCompletedEventArgs")
                {
                    CodeTypeReference typeref = (CodeTypeReference)eventArgsMap[type.Name];
                    
                    if (typeref == null)
                    {
                        continue;
                    }                    
                }

                // Skip if the delegate is not convertible.
                if (type is CodeTypeDelegate)
                {
                    if (!convertibleDelegates.Contains(type.Name))
                    {
                        continue;
                    }
                }

                // Keeps track of the index of the member being modified in this type.
				int memberIndex = 0;

				// BDS: 09-16-2005
				// Adding this hash table to store the old method names and their corresponding new method names. In this manner, 
				// I can quickly find the new method name for the sync method of an async method.
				Hashtable methodNamesMap = new Hashtable();

                // Keeps track of the new callback reference names with their original name.
                Hashtable callbacksMap = new Hashtable();

                // Keeps track of new event declaration names with their original name. 
                Hashtable eventsMap = new Hashtable();

                // Keeps tracks of delegate creation statements which has to be changed when the 
                // delegate name changes.
                Hashtable methodsMap = new Hashtable();

                Hashtable delegatesMap = new Hashtable();

                // BDS: 11-12-2006
                // Adding a hash table to hold the field name changes.
                Hashtable fieldsMap = new Hashtable();

                // Used to check whether the previously processed message is a wrapped mode method
                // or not.
                bool lastMethodWrapped = false;

				#region Change the Type Name, Public Field Names and Method Names.				

				foreach(CodeTypeMember member in type.Members)
				{					
					if(member is CodeMemberField)
					{						
						#region Change the field names.
                        
                        string oldFieldName = member.Name;

						if((member.Attributes & MemberAttributes.Private) == MemberAttributes.Private)
                        {
                            CodeMemberField fld = (CodeMemberField)member;
                            
                            if (fld.Type.BaseType == "System.Threading.SendOrPostCallback")
                            {
                                CallbackField cf = new CallbackField(fld);                                
                                callbacksMap.Add(fld.Name, cf);                                                                                               
                            }

                            // Modify the field name if this is an Enum type. Because Enum members are private.
                            if (type.IsEnum)
                            {
                                int counter = 0;
                                member.Name = GetPascalCaseName(member.Name);
                                string originalName = member.Name;

                                // Check whether the member name is same as the type name.
                                if (member.Name == GetPascalCaseName(type.Name))
                                {
                                    counter++;
                                    member.Name = originalName + counter.ToString();
                                }

                                // Check whether the member name is same as a member name a top of it.
                                CheckEnumMemberName:
                                for (int otherMemberIndex = 0; otherMemberIndex < memberIndex; otherMemberIndex++)
                                {
                                    CodeTypeMember otherMember = type.Members[otherMemberIndex];
                                    if (member.Name == otherMember.Name)
                                    {
                                        counter++;
                                        member.Name = originalName + counter.ToString();
                                        goto CheckEnumMemberName;
                                    }
                                } 
                            }
                        }
                        else if((member.Attributes & MemberAttributes.Public) == 
							MemberAttributes.Public || (member.Attributes & MemberAttributes.Final) == 
							MemberAttributes.Final)
						{
							// BDS: Fixed a bug here: We did not perform a check to make sure that the new 
							// member name is unique.
							int counter = 0;
							member.Name = GetPascalCaseName(member.Name);
							string originalName = member.Name;
			
							// Check whether the member name is same as the type name.
							if(member.Name == GetPascalCaseName(type.Name))
							{
								counter++;
								member.Name = originalName + counter.ToString();
							}

							// Check whether the member name is same as a member name a top of it.
                            CheckMemberName:
                            for(int otherMemberIndex = 0; otherMemberIndex < memberIndex; otherMemberIndex++)
							{
								CodeTypeMember otherMember = type.Members[otherMemberIndex];
								if(member.Name == otherMember.Name)
								{
									counter++;
									member.Name = originalName + counter.ToString();
                                    goto CheckMemberName;
								}
							}
						}
                        // BDS: 11-12-2006
                        // Add an entry to the field names dictionary.
                        if (member.Name != oldFieldName)
                            fieldsMap.Add(oldFieldName, member.Name);

						#endregion
					}
                    else if (member is CodeMemberEvent)
                    {
                        EventMember em = new EventMember((CodeMemberEvent)member, null, null);                        
                        eventsMap.Add(member.Name, em);
                        delegatesMap.Add(member.Name, ((CodeMemberEvent)member).Type.BaseType);
                    }
                    else if (member is CodeMemberMethod)
                    {
                        #region Change the method names.

                        CodeMemberMethod method = member as CodeMemberMethod;
                        bool isWrapped = IsDocLitWrapped(method);

                        // Change the method name. 
                        // Apply this conversion only if the method is a non-wrapped method.
                        if (!isWrapped)
                        {
                            // Async check: Check whether this is a async method. If it is a async method                             
                            // check the wrapped mode of the last method and act accordingly.
                            if (method.CustomAttributes.Count > 0 ||
                                (method.CustomAttributes.Count == 0 && !lastMethodWrapped))
                            {
                                lastMethodWrapped = false;

                                // BDS: 09-16-2005
                                // Modified the logic here. Earlier we did not check whether the current method is one of the 
                                // async method pair. Because of that the invoke statements in the async methods started to invoke 
                                // themselfs instead of invoking the corresponding sync method.
                                string modifiedName = "";

                                #region Check for Async Begin method.
                                
                                if (method.ReturnType.BaseType != null &&
                                    method.ReturnType.BaseType == "System.IAsyncResult")
                                {
                                    string originalMethodName = method.Name.Substring(5);
                                    modifiedName = (string)methodNamesMap[originalMethodName];

                                    if (modifiedName == null)
                                    {
                                        modifiedName = originalMethodName;
                                    }
                                    else
                                    {
                                        method.Name = string.Format("Begin{0}", modifiedName);
                                    }

                                    goto NextMember;
                                }

                                #endregion

                                #region Check for AsyncEnd method.

                                if (method.Parameters.Count > 0 &&
                                    method.Parameters[0].Type.BaseType != null &&
                                    method.Parameters[0].Type.BaseType == "System.IAsyncResult")
                                {
                                    string originalMethodName = method.Name.Substring(3);
                                    modifiedName = (string)methodNamesMap[originalMethodName];
                                    if (modifiedName == null)
                                    {
                                        modifiedName = originalMethodName;
                                    }
                                    else
                                    {
                                        method.Name = string.Format("End{0}", modifiedName);
                                    }

                                    goto NextMember;
                                }

                                #endregion

                                #region Check for the new Async methods.

                                if (method.CustomAttributes.Count == 0 && IsMatchingPattern(AsyncNamingPattern, method.Name))
                                {                                    
                                    string originalMethodName = method.Name;
                                    string asyncAutoTrailer = "";
                                    originalMethodName = originalMethodName.Substring(0, originalMethodName.LastIndexOf("Async"));

                                    if (method.Name.Length > method.Name.LastIndexOf("Async") + 5)
                                    {
                                        asyncAutoTrailer = method.Name.Substring(method.Name.LastIndexOf("Async") + 5);
                                    }

                                    modifiedName = (string)methodNamesMap[originalMethodName];

                                    if (modifiedName != null)
                                    {
                                        method.Name = string.Format("{0}Async{1}", modifiedName, asyncAutoTrailer);

                                        foreach (CodeStatement statement in method.Statements)
                                        {
                                            // See whether there is an statement which calls the overloaded 
                                            // async method. And if there is, change its name into pascal case.                                    
                                            if (statement is CodeExpressionStatement)
                                            {
                                                CodeMethodInvokeExpression overloadedAsync =
                                                    ((CodeExpressionStatement)statement).Expression as CodeMethodInvokeExpression;

                                                if (overloadedAsync != null &&
                                                    overloadedAsync.Method.TargetObject is CodeThisReferenceExpression &&
                                                    overloadedAsync.Method.MethodName == originalMethodName + "Async" + asyncAutoTrailer)
                                                {
                                                    overloadedAsync.Method.MethodName = method.Name;
                                                    continue; // Continue to the next code statement.
                                                }
                                            }

                                            // Change the method names and field names found in the 
                                            // async method implementation.

                                            CodeConditionStatement ifCallbackNull =
                                                statement as CodeConditionStatement;

                                            if (ifCallbackNull != null)
                                            {
                                                // Change the callback field name.
                                                CodeBinaryOperatorExpression callbacknull =
                                                    ifCallbackNull.Condition as CodeBinaryOperatorExpression;

                                                if (callbacknull != null)
                                                {
                                                    CodeFieldReferenceExpression field =
                                                        callbacknull.Left as CodeFieldReferenceExpression;

                                                    if (field != null)
                                                    {
                                                        CallbackField cf = (CallbackField)callbacksMap[field.FieldName];
                                                        cf.FieldReference = field;                                                        
                                                    }
                                                }

                                                if (ifCallbackNull.TrueStatements.Count > 0)
                                                {
                                                    CodeAssignStatement assignCallback =
                                                        ifCallbackNull.TrueStatements[0] as CodeAssignStatement;

                                                    if (assignCallback != null)
                                                    {
                                                        // Change the callback initialization statement.
                                                        CodeDelegateCreateExpression initcallback =
                                                            assignCallback.Right as CodeDelegateCreateExpression;

                                                        if (initcallback != null)
                                                        {
                                                            methodsMap.Add(initcallback.MethodName, initcallback);
                                                        }
                                                    }
                                                }
                                                continue; // Continue to the next code statement.
                                            }


                                            // Change the async invoke method.
                                            CodeMethodInvokeExpression callAsync =
                                                ((CodeExpressionStatement)statement).Expression as CodeMethodInvokeExpression;

                                            if (callAsync != null)
                                            {
                                                if (callAsync.Method.MethodName == "InvokeAsync")
                                                {
                                                    CodePrimitiveExpression p1 =
                                                        callAsync.Parameters[0] as CodePrimitiveExpression;

                                                    if (p1 != null)
                                                    {
                                                        p1.Value = modifiedName;
                                                    }

                                                    CodeFieldReferenceExpression p3 =
                                                        callAsync.Parameters[2] as CodeFieldReferenceExpression;

                                                    if (p3 != null)
                                                    {
                                                        CallbackField cf = (CallbackField)callbacksMap[p3.FieldName];
                                                        cf.FieldReference2 = p3;
                                                    }
                                                }
                                                continue; // Continue to next statement.
                                            }
                                        }
                                        goto NextMember;
                                    } // if (modifiedName != null)
                                } // if (method.Name.EndsWith("Async"))

                                #endregion

                                #region Check for the new Async Callback method.

                                if (method.Name.StartsWith("On") && method.Name.EndsWith("OperationCompleted") && 
                                    method.CustomAttributes.Count == 0)
                                {
                                    string originalMethodName = method.Name;
                                    originalMethodName = originalMethodName.Substring(2, originalMethodName.Length - 20);
                                    modifiedName = (string)methodNamesMap[originalMethodName];

                                    if (modifiedName != null)
                                    {
                                        string oldMethodName = method.Name;
                                        method.Name = string.Format("On{0}OperationCompleted", modifiedName);

                                        CodeDelegateCreateExpression methodReference =
                                            (CodeDelegateCreateExpression)methodsMap[oldMethodName];

                                        methodReference.MethodName = method.Name;

                                        // Get the first statement which is the null validation for the event.
                                        CodeConditionStatement ifnullevent = method.Statements[0] as
                                            CodeConditionStatement;

                                        // Change the event name.
                                        CodeBinaryOperatorExpression nullevent = ifnullevent.Condition as
                                            CodeBinaryOperatorExpression;

                                        CodeEventReferenceExpression eventref = nullevent.Left as
                                            CodeEventReferenceExpression;

                                        EventMember em = (EventMember)eventsMap[eventref.EventName];
                                        em.EventReference = eventref;

                                        string delageTypeName = (string)delegatesMap[eventref.EventName];

                                        if (delageTypeName != null)
                                        {
                                            convertibleDelegates.Add(delageTypeName);
                                        }
                                        
                                        // Get the event invoke statement and change the event name and the 
                                        // event args(2nd one) parameter.
                                        CodeDelegateInvokeExpression eventInvoke =
                                            ((CodeExpressionStatement)ifnullevent.TrueStatements[1]).Expression as CodeDelegateInvokeExpression;

                                        em.EventInvoke = ((CodeEventReferenceExpression)eventInvoke.TargetObject);
                                        
                                        // Change the event args type.
                                        CodeObjectCreateExpression eventargs = eventInvoke.Parameters[1] as
                                            CodeObjectCreateExpression;

                                        if (eventargs.CreateType.BaseType != "System.ComponentModel.AsyncCompletedEventArgs")
                                        {
                                            eventArgsMap.Add(eventargs.CreateType.BaseType, eventargs.CreateType);
                                        }

                                        goto NextMember;
                                    } // if (modifiedName != null)
                                } // if (method.Name.StartsWith("On") && method.Name.EndsWith("OperationCompleted"))

                                #endregion

                                // Perform the default conversion if this method is the sync version. 
                                // Typically the async methods genrated by SDI are not decorated with 
                                // any custom attribute. 
                                if (method.CustomAttributes.Count > 0)
                                {
                                    // Default method name conversion.
                                    string omn = method.Name;	// Preserve the old method name.
                                    string alias;
                                    string newAlias;

                                    SetUniquePascalCaseMethodName(type, method, out alias, out newAlias);

                                    if (newAlias == null)
                                    {
                                        // Add a new entry in the method names map.
                                        methodNamesMap.Add(omn, method.Name);
                                        modifiedName = method.Name;
                                    }
                                    else
                                    {
                                        methodNamesMap.Add(alias, newAlias);
                                        modifiedName = newAlias;
                                    }
                                }

                            NextMember:
                                #region Change the method name in the method statements.

                                foreach (CodeStatement statement in method.Statements)
                                {
                                    #region Change the method invocation statement in variable declaraions.

                                    CodeVariableDeclarationStatement varDcl =
                                        statement as CodeVariableDeclarationStatement;
                                    if (varDcl != null)
                                    {
                                        CodeMethodInvokeExpression invoke =
                                            varDcl.InitExpression as CodeMethodInvokeExpression;

                                        if (invoke != null && invoke.Method.TargetObject is
                                            CodeThisReferenceExpression &&
                                            invoke.Method.MethodName == "Invoke")
                                        {
                                            invoke.Parameters[0] =
                                                new CodePrimitiveExpression(modifiedName);
                                            continue;
                                        }
                                    }
                                    
                                    #endregion

                                    #region Change the method invocatoin statement in the return statement.
                                    CodeMethodReturnStatement retStatement = statement as CodeMethodReturnStatement;
                                    if (retStatement != null && retStatement.Expression != null &&
                                        retStatement.Expression is CodeMethodInvokeExpression)
                                    {
                                        CodeMethodInvokeExpression invoke =
                                            retStatement.Expression as CodeMethodInvokeExpression;

                                        if (invoke.Method.TargetObject is
                                            CodeThisReferenceExpression &&
                                            invoke.Method.MethodName == "BeginInvoke")
                                        {
                                            invoke.Parameters[0] =
                                                new CodePrimitiveExpression(modifiedName);
                                        }
                                        continue;
                                    }
                                    #endregion

                                    #region Change the method invocation statement.
                                    CodeExpressionStatement expStatement =
                                        statement as CodeExpressionStatement;
                                    if (expStatement != null)
                                    {
                                        CodeMethodInvokeExpression invokeStatement =
                                            expStatement.Expression as CodeMethodInvokeExpression;
                                        if (invokeStatement != null)
                                        {
                                            if (invokeStatement.Method.TargetObject is
                                                CodeThisReferenceExpression &&
                                                invokeStatement.Method.MethodName == "Invoke")
                                            {
                                                invokeStatement.Parameters[0] =
                                                    new CodePrimitiveExpression(modifiedName);
                                            }
                                            continue;
                                        }
                                    }
                                    #endregion
                                }
                                #endregion
                            }
                        } // if(!isWrapped)
                        else
                        {
                            // Last method is not a wrapped mode method.
                            lastMethodWrapped = true;
                        }

                        #region Change the member names refered by the SOAP header attribute.
                        foreach (CodeAttributeDeclaration methodAttribute in method.CustomAttributes)
                        {
                            if (methodAttribute.Name ==
                                "System.Web.Services.Protocols.SoapHeaderAttribute")
                            {
                                foreach (CodeAttributeArgument arg in methodAttribute.Arguments)
                                {
                                    if (arg.Name == "" || arg.Name == "MemberName")
                                    {
                                        CodePrimitiveExpression pe =
                                            methodAttribute.Arguments[0].Value as CodePrimitiveExpression;
                                        if (pe != null)
                                        {
                                            methodAttribute.Arguments[0].Value =
                                                new CodePrimitiveExpression(
                                                GetPascalCaseName(pe.Value.ToString()));
                                        }
                                    }
                                }
                            }
                        }
                        #endregion
                        #endregion
                    } // else if (member is CodeMemberMethod)
                
					memberIndex++;
                } // foreach (CodeTypeMember member in type.Members)

                #region Change the callback member names and the references.
                
                // Once the members are processed modify the callback field members and
                // their references.
                foreach (string fldName in callbacksMap.Keys)
                {
                    CallbackField cf = (CallbackField)callbacksMap[fldName];

                    if (cf.FieldReference != null)
                    {
                        int counter = 0;
                        string nameBeforeConversion = cf.Field.Name;
                        string newName = GetPascalCaseName(nameBeforeConversion);
                        string originalName = cf.Field.Name;

                        // Check whether the member name is same as the type name.
                        if (newName == GetPascalCaseName(type.Name))
                        {
                            counter++;
                            newName = originalName + counter.ToString();
                        }

                        // Check whether the member name is same as another member name.
                    CheckCallbackName:
                        foreach(CodeTypeMember otherMember in type.Members)
                        {                                          
                            if (otherMember != cf.Field && newName == otherMember.Name)
                            {
                                counter++;
                                newName = originalName + counter.ToString();
                                goto CheckCallbackName;
                            }
                        }

                        cf.Field.Name = newName;
                        cf.FieldReference.FieldName = newName;
                        cf.FieldReference2.FieldName = newName;

                    } // if (cf.FieldReference != null)
                } // foreach (string fldName in callbacksMap.Keys)

                #endregion

                #region Change the event member names and the references.

                // Once the members are processed modify the callback field members and
                // their references.
                foreach (string evtName in eventsMap.Keys)
                {
                    EventMember em = (EventMember)eventsMap[evtName];

                    if (em.EventReference != null)
                    {
                        int counter = 0;
                        string nameBeforeConversion = em.EventDeclaration.Name;
                        string newName = GetPascalCaseName(nameBeforeConversion);
                        string originalName = newName;

                        // Check whether the member name is same as the type name.
                        if (newName == GetPascalCaseName(type.Name))
                        {
                            counter++;
                            newName = originalName + counter.ToString();
                        }

                        // Check whether the member name is same as another member name.
                    CheckCallbackName:
                        foreach (CodeTypeMember otherMember in type.Members)
                        {
                            if(otherMember!= em.EventDeclaration && newName == otherMember.Name)
                            {
                                counter++;
                                newName = originalName + counter.ToString();
                                goto CheckCallbackName;
                            }
                        }

                        em.EventDeclaration.Name = newName;
                        em.EventReference.EventName = newName;
                        em.EventInvoke.EventName = newName;

                    } // if (cf.FieldReference != null)
                } // foreach (string fldName in callbacksMap.Keys)

                #endregion
                
                #region Change the type name
                // BDS: Fixed a bug here. We did not perform a check to make sure the type name generated is 
				// unique to the namespace.
				typeIndex++;
				string originalTypeName = type.Name; // Preserve the original type name to change the variable declarations.
				type.Name = GetPascalCaseName(type.Name);					
				string newTypeName = type.Name;
				int typeNameCounter = 0;

				for(int otherTypeIndex = 0; otherTypeIndex < typeIndex; otherTypeIndex++)
				{
					CodeTypeDeclaration otherType = cns.Types[otherTypeIndex];
					if(otherType.Name == newTypeName)
					{
						typeNameCounter++;
						newTypeName = type.Name + typeNameCounter.ToString();
					}
				}
				
                type.Name = newTypeName;
				#endregion

                #region Change the field names referenced in the ctor

                // BDS: 11-11-2006
                // Fixed a bug here. We have to change the field references in the 
                // constructor. 
                foreach (CodeTypeMember member in type.Members)
                {
                    CodeConstructor ctor = member as CodeConstructor;
                    if (ctor != null)
                    {   
                        // Look for the assignment statements and change casing
                        // in the field references.
                        foreach (CodeStatement statement in ctor.Statements)
                        {
                            CodeAssignStatement assign = statement as CodeAssignStatement;
                            if (assign != null)
                            {
                                CodeFieldReferenceExpression lref = assign.Left as CodeFieldReferenceExpression;
                                if (lref != null)
                                {                                    
                                    CodeThisReferenceExpression thisref = lref.TargetObject as CodeThisReferenceExpression;
                                    if (thisref != null)
                                    {
                                        if (fieldsMap.Contains(lref.FieldName))
                                        {
                                            lref.FieldName = (string)fieldsMap[lref.FieldName];
                                        }
                                    }
                                }
                            }
                        }
                        break;
                    }
                }

                #endregion
                
                #endregion

                #region Change the public fields, properties, parameters and return types of this type to use the new type name.

                if (type.BaseTypes.Count == 1 && 
                    type.BaseTypes[0].BaseType == "System.ComponentModel.AsyncCompletedEventArgs")
                {
                    CodeTypeReference typeref = (CodeTypeReference)eventArgsMap[originalTypeName];
                    typeref.BaseType = type.Name;
                }
                
                foreach(CodeTypeDeclaration lookinType in cns.Types)
				{
                    if (lookinType is CodeTypeDelegate)
                    {
                        CodeTypeDelegate dlg = (CodeTypeDelegate)lookinType;
                        if (dlg.Parameters[1].Type.BaseType == originalTypeName)
                        {
                            dlg.Parameters[1].Type.BaseType = type.Name;
                        }
                        continue;
                    }

					foreach(CodeTypeMember member in lookinType.Members)							
					{
						#region Change public field declarations.

						if(member is CodeMemberField)
						{
							CodeMemberField fld = member as CodeMemberField;
							// BDS: Fixed a bug here. Added code to convert the array type names.
							if(fld.Type.ArrayElementType != null)
							{
								if(fld.Type.ArrayElementType.BaseType == originalTypeName)
								{
									fld.Type.ArrayElementType.BaseType = type.Name;                                    
								}
							}
							else
							{
                                if (fld.Type.TypeArguments.Count == 0)
                                {
                                    if (fld.Type.BaseType == originalTypeName)
                                    {
                                        fld.Type.BaseType = type.Name;
                                    }
                                }
                                else
                                {
                                    // Check for the code type arguments for generic type fields.
                                    foreach (CodeTypeReference gtype in fld.Type.TypeArguments)
                                    {
                                        if (gtype.BaseType == originalTypeName)
                                        {
                                            gtype.BaseType = type.Name;
                                        }
                                    }
                                }
							}

                            ConvertTypeOfArgumentInCustomAttributes(fld.CustomAttributes, originalTypeName, type.Name);
                            if(type.IsEnum)
                                ChangeDefaultValueCustomAttribute(fld.CustomAttributes, originalTypeName, type.Name, fieldsMap);
                            continue; // Next member.
						}

						#endregion

                        #region Change the public event declarations.

                        if (member is CodeMemberEvent)
                        {
                            CodeMemberEvent evt = (CodeMemberEvent)member;
                            if (evt.Type.BaseType == originalTypeName)
                            {
                                evt.Type.BaseType = type.Name;
                                continue; // Next member.
                            }
                        }

                        #endregion

                        #region Change the puplic property declarations.

                        if (member is CodeMemberProperty)
                        {
#if ATTPROATPC // Attention! Property at Pascal Conversion.
                            Debug.Assert(false, 
                                string.Format("ATTENTION: UsePascalCase procedure entered a property block.\nType:{0}\nMember:{1}", 
                                lookinType.Name, member.Name));
#endif

                            CodeMemberProperty property = (CodeMemberProperty)member;

                            if (property.Type.BaseType == originalTypeName)
                            {
                                property.Type.BaseType = type.Name;
                            }

                            foreach (CodeStatement gstmnt in property.GetStatements)
                            {
                                if (gstmnt is CodeMethodReturnStatement)
                                {
                                    CodeMethodReturnStatement ret = (CodeMethodReturnStatement)gstmnt;
                                    CodeCastExpression cast = ret.Expression as CodeCastExpression;
                                    
                                    if (cast != null)
                                    {
                                        if (cast.TargetType.BaseType == originalTypeName)
                                        {
                                            cast.TargetType.BaseType = type.Name;
                                        }
                                    }
                                }
                            }

                            ConvertTypeOfArgumentInCustomAttributes(property.CustomAttributes, originalTypeName, type.Name);
                            if(type.IsEnum)
                                ChangeDefaultValueCustomAttribute(property.CustomAttributes, originalTypeName, type.Name, fieldsMap);
                            continue; // Next member.
                        }
                        
                        #endregion

                        #region Change the method parameter type and return type and type cast statements.
                        
                        CodeMemberMethod method = member as CodeMemberMethod;
						
                        if(method != null)
						{	

							#region Change the parameter type names.

							foreach(CodeParameterDeclarationExpression param in method.Parameters)
							{
								if(param.Type.ArrayElementType != null)
								{
									if(param.Type.ArrayElementType.BaseType == originalTypeName)
									{
										param.Type.ArrayElementType.BaseType = type.Name;
                                        continue; // Next parameter.
									}
								}
								else
								{
									if(param.Type.BaseType == originalTypeName)
									{
										param.Type.BaseType = type.Name;
                                        continue; // Next parameter.
									}
								}
							}

							#endregion
	
							#region Change the return type name.

							// Change the method return types.
							if(method.ReturnType != null)
							{
								if(method.ReturnType.ArrayElementType != null)
								{
									if(method.ReturnType.ArrayElementType.BaseType == 
										originalTypeName)
									{
										method.ReturnType.ArrayElementType.BaseType = type.Name;										
										// Change the type name in the return statement.
										foreach(CodeStatement statement in method.Statements)
										{
											if(statement is CodeMethodReturnStatement)
											{
												CodeMethodReturnStatement returnStatement = 
													statement as CodeMethodReturnStatement;
						
												if(returnStatement.Expression != null && 
													returnStatement.Expression is CodeCastExpression)
												{
													CodeCastExpression cast = returnStatement.Expression as 
														CodeCastExpression;
													cast.TargetType.ArrayElementType.BaseType = type.Name														;
												}															
											}
										}
									}
								}
								else
								{
									if(method.ReturnType.BaseType == originalTypeName)
									{
										method.ReturnType.BaseType = type.Name;
										// Change the type name in the return statement.
										foreach(CodeStatement statement in method.Statements)
										{
											if(statement is CodeMethodReturnStatement)
											{
												CodeMethodReturnStatement returnStatement = 
													statement as CodeMethodReturnStatement;
						
												if(returnStatement.Expression != null && 
													returnStatement.Expression is CodeCastExpression)
												{
													CodeCastExpression cast = returnStatement.Expression as 
														CodeCastExpression;
													cast.TargetType.BaseType = type.Name;
												}												
											}
										}
									}
								}
                            } 

							#endregion

							#region Change the type names in the type cast statements.

							foreach(CodeStatement statement in method.Statements)
							{								
								CodeAssignStatement refAssign = statement as CodeAssignStatement;
								if(refAssign != null)
								{
									CodeCastExpression cast = refAssign.Right as CodeCastExpression;
									if(cast != null)
									{
										if(cast.TargetType.ArrayElementType != null)
										{
											if(cast.TargetType.ArrayElementType.BaseType == originalTypeName)
											{
												cast.TargetType.ArrayElementType.BaseType = type.Name;
											}
										}
										else
										{
											if(cast.TargetType.BaseType == originalTypeName)
											{
                                                cast.TargetType.BaseType = type.Name;												
											}
										}
										continue;
									}
								}								
							}

							#endregion 

                            ConvertTypeOfArgumentInCustomAttributes(method.CustomAttributes, originalTypeName, type.Name);
                            continue; // Next member.
                                           
                        } // if(method != null)

						#endregion

                        #region Change the assignment statements in the ctor.

                        // BDS 11-11-2006: Fixed a bug here. We have to change the 
                        // field references in the constructor.
                        CodeConstructor ctor = member as CodeConstructor;
                        if (ctor != null)
                        {
                            foreach (CodeStatement statement in ctor.Statements)
                            {
                                CodeAssignStatement assign = statement as CodeAssignStatement;
                                if (assign != null)
                                {
                                    CodeFieldReferenceExpression rref = assign.Right as CodeFieldReferenceExpression;
                                    if (rref != null)
                                    {
                                        CodeTypeReferenceExpression typeref = rref.TargetObject as CodeTypeReferenceExpression;
                                        if (typeref.Type.BaseType == originalTypeName)
                                        {
                                            typeref.Type.BaseType = type.Name;
                                            if (fieldsMap.Contains(rref.FieldName))
                                            {
                                                rref.FieldName = (string)fieldsMap[rref.FieldName];
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        #endregion
                    } // foreach(CodeTypeMember member in lookinType.Members)

					#region Change inherited type names.
					
                    foreach(CodeTypeReference ctr in  lookinType.BaseTypes)
					{
						if(ctr.BaseType == originalTypeName)
						{
							ctr.BaseType = type.Name;
						}
					}
					
                    #endregion

					#region Change the typeof arguments in the type attributes.
					
                    foreach(CodeAttributeDeclaration typeAttribute in lookinType.CustomAttributes)
					{
						if(typeAttribute.Name == "System.Xml.Serialization.XmlIncludeAttribute")
						{
							CodeTypeOfExpression arg = 
								typeAttribute.Arguments[0].Value as CodeTypeOfExpression;
							if(arg.Type.BaseType == originalTypeName)
							{
								arg.Type.BaseType = type.Name;
							}							
						}
					}
					
                    #endregion
				}
				#endregion
            } // foreach(CodeTypeDeclaration type in cns.Types)
		}

        /// <summary>
        /// Changes the type name used in the "TypeOf" argument the following XML attributes.
        /// 1. System.Xml.Serialization.XmlIncludeAttribute
        /// 2. System.Xml.Serialization.XmlArrayItemAttribute
        /// 3. System.Xml.Serialization.XmlElementAttribute
        /// 4. System.Xml.Serialization.XmlTextAttribute
        /// </summary>
        static void ConvertTypeOfArgumentInCustomAttributes(CodeAttributeDeclarationCollection customAttributes, 
            string oldTypeName, string newTypeName)
        {
            foreach (CodeAttributeDeclaration memberAttribute in customAttributes)
            {
                if (memberAttribute.Name == "System.Xml.Serialization.XmlIncludeAttribute" ||
                    memberAttribute.Name == "System.Xml.Serialization.XmlArrayItemAttribute" ||
                    memberAttribute.Name == "System.Xml.Serialization.XmlElementAttribute" ||
                    memberAttribute.Name == "System.Xml.Serialization.XmlTextAttribute")
                {
                    foreach (CodeAttributeArgument arg in memberAttribute.Arguments)
                    {
                        CodeTypeOfExpression typeOfExp = arg.Value as CodeTypeOfExpression;

                        if (typeOfExp != null)
                        {
                            if (typeOfExp.Type.BaseType == oldTypeName)
                            {
                                typeOfExp.Type.BaseType = newTypeName;
                            }                            
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Changes the field name used in the DefaultValueAttribute attribute.
        /// </summary>
        static void ChangeDefaultValueCustomAttribute(CodeAttributeDeclarationCollection customAttributes,
            string oldTypeName, 
            string newTypeName, 
            Hashtable fieldNamesMap)
        {
            foreach (CodeAttributeDeclaration memberAttribute in customAttributes)
            {
                if (memberAttribute.Name == "System.ComponentModel.DefaultValueAttribute")
                {
                    foreach (CodeAttributeArgument arg in memberAttribute.Arguments)
                    {
                        CodeFieldReferenceExpression typeOfExp = arg.Value as CodeFieldReferenceExpression;

                        if (typeOfExp != null)
                        {
                            CodeTypeReferenceExpression ctre = typeOfExp.TargetObject as CodeTypeReferenceExpression;
                            if(ctre != null)
                            {
                                if(ctre.Type.BaseType == oldTypeName)
                                {
                                    ctre.Type.BaseType = newTypeName;
                                    if(fieldNamesMap.ContainsKey(typeOfExp.FieldName))
                                    {
                                        typeOfExp.FieldName = (string)fieldNamesMap[typeOfExp.FieldName];
                                    }
                                }
                            }
                            break;
                        }
                    }
                    break;
                }
            }
        }

        /// <summary>
        /// This method generates a unique pascal case name for a given code DOM method.
        /// </summary>        
        static void SetUniquePascalCaseMethodName(CodeTypeDeclaration type, CodeTypeMember method, out string alias, 
            out string newAlias)
        {
            alias = null;
            newAlias = null;
            
            CodeAttributeArgument argument = GetAttributeArgument(method.CustomAttributes,
                "System.Web.Services.WebMethodAttribute", "MessageName");

            if (argument != null)
            {
                alias = ((CodePrimitiveExpression)argument.Value).Value.ToString();
                string pascalCaseAlias = GetPascalCaseName(alias);
                newAlias = pascalCaseAlias;
                int aliasCounter = 0;

                while (!IsNameUnique(newAlias, method, type))
                {
                    aliasCounter++;
                    newAlias = pascalCaseAlias + aliasCounter++;
                }

                argument.Value = new CodePrimitiveExpression(newAlias);
                method.Name = GetPascalCaseName(method.Name);
            }
            else
            {
                string pascalCaseMethodName = GetPascalCaseName(method.Name);
                method.Name = pascalCaseMethodName;
                int counter = 0;

                while (!IsNameUnique(method.Name, method, type))
                {
                    counter++;
                    method.Name = pascalCaseMethodName + counter.ToString();
                }
            }           
        }

        static bool IsNameUnique(string name, CodeTypeMember member, CodeTypeDeclaration type)
        {
            foreach (CodeTypeMember member2 in type.Members)
            {
                if (member != member2)
                {
                    if (name == member2.Name)
                    {
                        return false;
                    }
                    
                    CodeAttributeArgument argument = GetAttributeArgument(member2.CustomAttributes, "System.Web.Services.WebMethodAttribute",
                        "MessageName");

                    if (argument != null)
                    {
                        if (name == ((CodePrimitiveExpression)argument.Value).Value.ToString())
                        {
                            return false;
                        }
                    }
                }
                else
                {
                    // Do not process if the 'member' is 'member2'.
                    break;
                }
            }

            return true;
        }

        static bool IsMatchingPattern(string pattern, string value)
        {
            Regex regex = new Regex(pattern);
            Match match = regex.Match(value);
            return match.Success;
        }

        /// <summary>
        /// This method searches a given attribute and attribute argument within a collection of attributes and returns a reference 
        /// to it if available.
        /// </summary>        
        static CodeAttributeArgument GetAttributeArgument(CodeAttributeDeclarationCollection attributes, string attributeType, 
            string argumentName)
        {
            foreach (CodeAttributeDeclaration attribute in attributes)
            {
                if (attribute.AttributeType.BaseType == attributeType)
                {
                    foreach (CodeAttributeArgument argument in attribute.Arguments)
                    {
                        if (argument.Name == argumentName)
                        {
                            return argument;
                        }
                    }
                    break;
                }
            }

            return null;
        }

		/// <summary>
		/// Converts all the parameters names in all the methods of a given type to camel Case.
		/// </summary>
		/// <param name="type">Type declaration to perform the conversion.</param>
		/// <author>BDS</author>
		internal static void UseCamelCaseParameterNames(CodeNamespace cns)
		{
			foreach(CodeTypeDeclaration type in cns.Types)
			{				
				// Itterate through all the methods and convert the parameter names to 
				// camel case.
				foreach(CodeTypeMember member in type.Members)
				{
					CodeMemberMethod method = member as CodeMemberMethod;
					if(method != null)
					{												
						// BDS: Do not perform this conversion if the method is a wrapped style one.
						if(IsDocLitWrapped(method))
						{
							continue;
						}

						Hashtable newParameterNames = new Hashtable();
						int parameterIndex = 0;
						foreach(CodeParameterDeclarationExpression parameter in method.Parameters)
						{
							string key = method.Name + "." + parameter.Name;
							parameter.Name = GetCamelCaseName(parameter.Name);
							string originalName = parameter.Name;
							int counter = 0;

							if(parameter.Name == method.Name)
							{
								counter++;
								parameter.Name = originalName + counter.ToString();
							}
							
							for(int otherParameterIndex = 0; otherParameterIndex < parameterIndex; 
								otherParameterIndex++)
							{
								CodeParameterDeclarationExpression otherParameter = 
									method.Parameters[otherParameterIndex];
								if(otherParameter.Name == parameter.Name)
								{
									counter++;
									parameter.Name = originalName + counter.ToString();
								}
							}
							
							newParameterNames.Add(key, parameter.Name);
							parameterIndex++;
						}

						// Rename the parameter references.
						// TODO: Check for all types of statements and their parameter references and convert 
						// them to camel case.
						foreach(CodeStatement statement in method.Statements)
						{		
							// Check whether the statement is a variable declaration.
							CodeVariableDeclarationStatement vdecl = 
								statement as CodeVariableDeclarationStatement;
							if(vdecl != null)
							{
								CodeMethodInvokeExpression invoke = 
									vdecl.InitExpression as CodeMethodInvokeExpression;
								if(invoke != null)
								{
									foreach(CodeExpression parameterExp in invoke.Parameters)
									{
										// Check whether the parameterExp is a argument reference.
										CodeArgumentReferenceExpression parameterRef = 
											parameterExp as CodeArgumentReferenceExpression;
										if(parameterRef != null)
										{
											parameterRef.ParameterName = 
												(string)newParameterNames[method.Name + "." + parameterRef.ParameterName];
											// Go to next parameter expression.
											continue;
										}

										CodeArrayCreateExpression arrayExp = 
											parameterExp as CodeArrayCreateExpression;
										if(arrayExp != null)
										{
											// Check for argument references in the initializers.
											foreach(CodeExpression initExp in arrayExp.Initializers)
											{
												CodeArgumentReferenceExpression initParamRef = 
													initExp as CodeArgumentReferenceExpression;
												if(initParamRef != null)
												{
													initParamRef.ParameterName = 
														(string)newParameterNames[method.Name + "." + initParamRef.ParameterName];
												}
											}

											// Go to next parameter expression.
											continue;
										}
									}
								}
							
								// Goto the next statement.
								continue;
							}

							// Check whether the statement is a return statement.
							CodeMethodReturnStatement returnStatement = statement as CodeMethodReturnStatement;
							if(returnStatement != null)
							{
								CodeMethodInvokeExpression invoke = 
									returnStatement.Expression as CodeMethodInvokeExpression;
								if(invoke != null)
								{
									foreach(CodeExpression parameterExp in invoke.Parameters)
									{
										CodeArgumentReferenceExpression parameterRef = 
											parameterExp as CodeArgumentReferenceExpression;
										if(parameterRef != null)
										{
											parameterRef.ParameterName = 
												(string)newParameterNames[method.Name + "." + parameterRef.ParameterName];

											// Go to the next parameter expression.
											continue;
										}

										CodeArrayCreateExpression arrayExp = 
											parameterExp as CodeArrayCreateExpression;
										if(arrayExp != null)
										{
											// Check for argument references in the initializers.
											foreach(CodeExpression initExp in arrayExp.Initializers)
											{
												CodeArgumentReferenceExpression initParamRef = 
													initExp as CodeArgumentReferenceExpression;
												if(initParamRef != null)
												{
													initParamRef.ParameterName = 
														(string)newParameterNames[method.Name + "." + initParamRef.ParameterName];
												}
											}

											// Go to next parameter expression.
											continue;
										}
									}
								}

								// Go to the next statement.
								continue;
							}
						
							// Check whether the statement is a method invokation expression statement.
							CodeExpressionStatement expression = 
								statement as CodeExpressionStatement;
							if(expression != null)
							{
								CodeMethodInvokeExpression invoke = 
									expression.Expression as CodeMethodInvokeExpression;
								if(invoke != null)
								{
									foreach(CodeExpression parameterExp in invoke.Parameters)
									{
										CodeArgumentReferenceExpression parameterRef = 
											parameterExp as CodeArgumentReferenceExpression;
										if(parameterRef != null)
										{
											parameterRef.ParameterName = 
												(string)newParameterNames[method.Name + "." + parameterRef.ParameterName];

											// Go to the next parameter expression.
											continue;
										}

										CodeArrayCreateExpression arrayExp = 
											parameterExp as CodeArrayCreateExpression;
										if(arrayExp != null)
										{
											// Check for argument references in the initializers.
											foreach(CodeExpression initExp in arrayExp.Initializers)
											{
												CodeArgumentReferenceExpression initParamRef = 
													initExp as CodeArgumentReferenceExpression;
												if(initParamRef != null)
												{
													initParamRef.ParameterName = 
														(string)newParameterNames[method.Name + "." + initParamRef.ParameterName];
												}
											}

											// Go to next parameter expression.
											continue;
										}
									}
								}

								// Go to the next statement.
								continue;
							}

							// Check whether the statement is a code assignment expression.
							CodeAssignStatement assign = statement as CodeAssignStatement;
							if(assign != null)
							{
								CodeArgumentReferenceExpression paramref = 
									assign.Left as CodeArgumentReferenceExpression;
							
								if(paramref != null)
								{
									paramref.ParameterName = 
										(string)newParameterNames[method.Name + "." + paramref.ParameterName];
								}
							}
						}
					}
				}
			}
		}

		/// <summary>
		/// Accepts a string and converts it to Pascal Case.
		/// </summary>
		/// <param name="name">String to be converted.</param>
		/// <returns>A string containing the converted name.</returns>
		internal static string GetPascalCaseName(string name)
		{
			string tname = name;
			if(namingConventionsApplicable)
			{
				tname = name.Substring(0, 1).ToUpper();
				if(name.Length > 1)
				{
					tname += name.Substring(1);
				}
			}
			return tname;
		}

		/// <summary>
		/// Accepts a string and converts it to Camel Case.
		/// </summary>
		/// <param name="name">String to be converted.</param>
		/// <returns>A string containing the converted name.</returns>
		internal static string GetCamelCaseName(string name)
		{
			string tname = name;
			if(namingConventionsApplicable)
			{
				tname = name.Substring(0, 1).ToLower();
				if(name.Length > 1)
				{
					tname += name.Substring(1);
				}
			}
			return tname;
		}

		/// <summary>
		/// 
		/// </summary>		
		internal static void EmitXmlElementAttribute(CodeNamespace cns)
		{
			foreach(CodeTypeDeclaration type in cns.Types)
			{
                // Don't add the XML element attributes for the delegate types and 
                // EventArgs types.
                if (type is CodeTypeDelegate)
                {
                    continue;
                }

                if (type.BaseTypes.Count == 1 &&
                    type.BaseTypes[0].BaseType == "System.ComponentModel.AsyncCompletedEventArgs")
                {
                    continue;
                }

				// Add the XmlTypeAttribute to all the types except the service/proxy implementation types.
                // Also add the type name to the XmlRootAttribute if necessary.
				if((type.BaseTypes.Count == 0) ||
					((type.BaseTypes.Count > 0) && 
					(type.BaseTypes[0].BaseType != "System.Web.Services.WebService" &&
					type.BaseTypes[0].BaseType != "System.Web.Services.Protocols.SoapHttpClientProtocol" &&
					type.BaseTypes[0].BaseType != 
					"Thinktecture.Tools.Web.Services.Extensions.SoapHttpClientProtocolExtended")))
				{
					// Preserve the XML type name in the XmlTypeAttribute.	
					// BDS: Modified the code to use the new helper method 'AddAttribute'.
					CodeAttributeDeclaration xmlType = 
						new CodeAttributeDeclaration("System.Xml.Serialization.XmlTypeAttribute", 
						new CodeAttributeArgumentExtended("TypeName", 
						new CodePrimitiveExpression(type.Name), true));
                    
					AddAttribute(type.CustomAttributes, xmlType);
                    
                    // BDS (10/31/2006): Fixed a bug here. Added code to preserve the type name in the 
                    // XmlRootAttribute attribute. 
                    bool elementnamefound = false;                   
                    CodeAttributeDeclaration xmlRoot = HasAttribute("System.Xml.Serialization.XmlRootAttribute", type.CustomAttributes);
                    if (xmlRoot != null)
                    {
                        foreach (CodeAttributeArgument attribarg in xmlRoot.Arguments)
                        {
                            if (attribarg.Name == "ElementName")
                            {
                                elementnamefound = true;
                                break;
                            }
                        }
                        if(!elementnamefound)
                        {
                            CodeAttributeArgument elementname = new CodeAttributeArgument("ElementName",
                                new CodePrimitiveExpression(type.Name));
                            xmlRoot.Arguments.Add(elementname);
                        }
                    }
				}

				// Decorate the classes.
				if(type.IsClass)
				{								
					foreach(CodeTypeMember member in type.Members)
					{
						if((member.Attributes & MemberAttributes.Public) == MemberAttributes.Public)
						{
							// Add the attribute to the public field/property.
							if(member is CodeMemberField)
							{									
								CodeMemberField field = member as CodeMemberField;
								if(HasAttribute(
									"System.Xml.Serialization.XmlAttributeAttribute", 
									field.CustomAttributes) != null)
								{
									// Add XmlAttributeAttribute.
									CodeAttributeDeclaration xmlAttributeAttribute = 
										new CodeAttributeDeclaration("System.Xml.Serialization.XmlAttributeAttribute", 
										new CodeAttributeArgumentExtended(
										"AttributeName", new CodePrimitiveExpression(member.Name), true));
									AddAttribute(field.CustomAttributes, xmlAttributeAttribute);								
								}
								else if(field.Type.ArrayElementType == null)
								{	
									// Do not apply the XmlElementAttribute if any of the following attributes are 
									// already available.
									if(HasAttribute(
										"System.Xml.Serialization.XmlTextAttribute", 
										field.CustomAttributes) != null || 
										HasAttribute(
										"System.Xml.Serialization.XmlIgnoreAttribute", 
										field.CustomAttributes) != null || 
										HasAttribute(
										"System.Xml.Serialization.XmlAnyElementAttribute",
										field.CustomAttributes) != null || 
										HasAttribute(
										"System.Xml.Serialization.XmlAnyAttributeAttribute", 
										field.CustomAttributes) != null)
									{
										continue;
									}
									
									// Add the XmlElementAttribute
									CodeAttributeDeclaration xmlElementAttribute = 
										new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute", 
											new CodeAttributeArgumentExtended(
												"ElementName", new CodePrimitiveExpression(member.Name), true));
									AddAttribute(field.CustomAttributes, xmlElementAttribute);
                                } // else if(field.Type.ArrayElementType == null)
								else
								{
									// Do not apply the XmlArrayAttribute if any of the following attributes are 
									// already available.
                                    // BDS on 10/03/2006: adding a fix:
                                    // Sometimes XmlElement attribute is applied to the arrays. In that case
                                    // we have to makesure that the ElementName argument is emitted properly.
                                    //
                                    bool hasxe;
                                    if ((hasxe = HasAttribute(
                                        "System.Xml.Serialization.XmlElementAttribute",
                                        field.CustomAttributes) != null) ||
                                        HasAttribute(
                                        "System.Xml.Serialization.XmlTextAttribute",
                                        field.CustomAttributes) != null ||
                                        HasAttribute(
                                        "System.Xml.Serialization.XmlAnyElementAttribute",
                                        field.CustomAttributes) != null ||
                                        HasAttribute(
                                        "System.Xml.Serialization.XmlAnyAttributeAttribute",
                                        field.CustomAttributes) != null)
                                    {
                                        if (hasxe)
                                        {
                                            CodeAttributeDeclaration xmlElementAttribute =
                                                new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute",
                                                                                new CodeAttributeArgumentExtended(
                                                                                    "ElementName", 
                                                                                    new CodePrimitiveExpression(
                                                                                        member.Name), 
                                                                                true)
                                                                            );
                                            AddAttribute(field.CustomAttributes, xmlElementAttribute);								
                                        }
                                        continue;
                                    }
									
									// Add the XmlArrayAttribute.
									CodeAttributeDeclaration xmlArrayAttribute = 
										new CodeAttributeDeclaration("System.Xml.Serialization.XmlArrayAttribute", 
											new CodeAttributeArgumentExtended(
												"ElementName", new CodePrimitiveExpression(member.Name), true));
									AddAttribute(field.CustomAttributes, xmlArrayAttribute);
								} // else

								continue;
                            } // if(member is CodeMemberField)
					
							// Apply XmlElementAttribute/XmlArrayAttribute to the method parameters.
							if(member is CodeMemberMethod)
							{
								CodeMemberMethod method = member as CodeMemberMethod;

                                if (method.CustomAttributes.Count > 0)
                                {
                                    // Apply the attributes to the parameters.
                                    foreach (CodeParameterDeclarationExpression parameter in method.Parameters)
                                    {
                                        if (HasAttribute(
                                            "System.Xml.Serialization.XmlAttributeAttribute",
                                            parameter.CustomAttributes) != null)
                                        {
                                            // Add the AttributeName argument.
                                            CodeAttributeDeclaration xmlAttributeAttribute =
                                                new CodeAttributeDeclaration("System.Xml.Serialization.XmlAttributeAttribute",
                                                new CodeAttributeArgumentExtended(
                                                "AttributeName", new CodePrimitiveExpression(parameter.Name), true));
                                            AddAttribute(parameter.CustomAttributes, xmlAttributeAttribute);
                                        }
                                        else if (parameter.Type.ArrayElementType == null)
                                        {
                                            // Do not apply the XmlElementAttribute if any of the following attributes are 
                                            // already available.
                                            if (HasAttribute(
                                                    "System.Xml.Serialization.XmlTextAttribute",
                                                    parameter.CustomAttributes) != null ||
                                                HasAttribute(
                                                    "System.Xml.Serialization.XmlIgnoreAttribute",
                                                    parameter.CustomAttributes) != null ||
                                                HasAttribute(
                                                    "System.Xml.Serialization.XmlAnyElementAttribute",
                                                    parameter.CustomAttributes) != null ||
                                                HasAttribute(
                                                    "System.Xml.Serialization.XmlAnyAttributeAttribute",
                                                    parameter.CustomAttributes) != null)
                                            {
                                                continue;
                                            }

                                            // Add the XmlElementAttribute
                                            CodeAttributeDeclaration xmlElementAttribute =
                                                new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute",
                                                new CodeAttributeArgumentExtended(
                                                "ElementName", new CodePrimitiveExpression(parameter.Name), true));
                                            AddAttribute(parameter.CustomAttributes, xmlElementAttribute);
                                        } // else if (parameter.Type.ArrayElementType == null)
                                        else
                                        {
                                            // Do not apply the XmlArrayAttribute if any of the following attributes are 
                                            // already available.
                                            // BDS on 10/03/2006: adding a fix:
                                            // Sometimes XmlElement attribute is applied to the arrays. In that case
                                            // we have to makesure that the ElementName argument is emitted properly.
                                            // 
                                            bool hasxe;
                                            if ((hasxe = HasAttribute(
                                                    "System.Xml.Serialization.XmlElementAttribute",
                                                    parameter.CustomAttributes) != null) ||
                                                HasAttribute(
                                                    "System.Xml.Serialization.XmlTextAttribute",
                                                    parameter.CustomAttributes) != null ||
                                                HasAttribute(
                                                    "System.Xml.Serialization.XmlAnyElementAttribute",
                                                    parameter.CustomAttributes) != null ||
                                                HasAttribute(
                                                    "System.Xml.Serialization.XmlAnyAttributeAttribute",
                                                    parameter.CustomAttributes) != null)
                                            {                                                
                                                if (hasxe)
                                                {                                                    
                                                    // Add the XmlElementAttribute
                                                    CodeAttributeDeclaration xmlElementAttribute =
                                                        new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute",
                                                        new CodeAttributeArgumentExtended(
                                                        "ElementName", new CodePrimitiveExpression(parameter.Name), true));
                                                    AddAttribute(parameter.CustomAttributes, xmlElementAttribute);
                                                }
                                                continue;
                                            }

                                            // Add the XmlArrayAttribute.
                                            CodeAttributeDeclaration xmlArrayAttribute =
                                                new CodeAttributeDeclaration("System.Xml.Serialization.XmlArrayAttribute",
                                                new CodeAttributeArgumentExtended(
                                                "ElementName", new CodePrimitiveExpression(parameter.Name), true));
                                            AddAttribute(parameter.CustomAttributes, xmlArrayAttribute);
                                        } // else
                                    } // foreach(CodeParameterDeclarationExpression parameter in method.Parameters)
                                } // if (method.CustomAttributes.Count > 0)
								continue;
                            } // if(member is CodeMemberMethod)
                        } // if((member.Attributes & MemberAttributes.Public) == MemberAttributes.Public)
                    } // foreach(CodeTypeMember member in type.Members)
					continue;
                } // if(type.IsClass)

				// Decorate the enumeration members with XmlEnumAttribute.
				if(type.IsEnum)
				{
					foreach(CodeTypeMember member in type.Members)
					{
						// Do not apply the XmlEnumAttribute if any of the following attributes are 
						// already available.
						if(HasAttribute(
							"System.Xml.Serialization.XmlAttributeAttribute", 
							member.CustomAttributes) != null || 
							HasAttribute(
							"System.Xml.Serialization.XmlAnyElementAttribute",
							member.CustomAttributes) != null || 
							HasAttribute(
							"System.Xml.Serialization.XmlAnyAttributeAttribute", 
							member.CustomAttributes) != null)
						{
							continue;
						}

						// Add XmlEnumAttribute
						CodeAttributeDeclaration xmlEnum = new CodeAttributeDeclaration
							("System.Xml.Serialization.XmlEnumAttribute");
						xmlEnum.Arguments.Add(new CodeAttributeArgumentExtended("Name", 
							new CodePrimitiveExpression(member.Name), true));
						AddAttribute(member.CustomAttributes, xmlEnum);
					}

					continue;
				}
			}
		}

		
		/// <summary>
		/// This is a helper method to add a new attribute to a attributes collection or modify an existing attribute.
		/// It checks whether a given attribute exists and adds it if its not there. If it is there, then it will
		/// add the arguments available in the new attribute but not available in the existing attribute.
		/// </summary>
		/// <param name="attributes">CodeAttributeDeclarationCollection object to add/modify attribute.</param>
		/// <param name="attribute">CodeAttributeDeclaration object to add to the collection.</param>
		private static void AddAttribute(CodeAttributeDeclarationCollection attributes, 
			CodeAttributeDeclaration attribute)
		{	
			bool attributeFound = false; 
			foreach(CodeAttributeDeclaration exAttribute in attributes)
			{				
				if(exAttribute.Name == attribute.Name)
				{
					attributeFound = true;
					CodeAttributeArgumentCollection argumentsAdded = new CodeAttributeArgumentCollection();

					foreach(CodeAttributeArgument newArg in attribute.Arguments)
					{
						CodeAttributeArgumentExtended extendedNewArg = 
							newArg as CodeAttributeArgumentExtended;
						bool argumentFound = false;

						foreach(CodeAttributeArgument exArg in exAttribute.Arguments)
						{
							if(exArg.Name == newArg.Name || 
								(extendedNewArg != null && extendedNewArg.Default && 
									exArg.Name == ""))
							{
								argumentFound = true;
								break;
							}
						}
						
						if(!argumentFound)
						{
							argumentsAdded.Add(newArg);
						}
					}
					
					exAttribute.Arguments.AddRange(argumentsAdded);
					break;
				}				
			}

			if(!attributeFound)
			{
				attributes.Add(attribute);
			}
		}

        /// <summary>
        /// Checks whether a given type or any of it's parents (who lives in the same namespace) 
        /// in the inheritence tree implements the given interface.
        /// </summary>
        /// <param name="cns">The code namespace that the type belongs to.</param>
        /// <param name="type">Type to be checked.</param>
        /// <param name="fqinterface">Fully qulified name of the interface to be checked.</param>
        /// <returns>true or false indicating whether the type implements the fqinterface or not.</returns>
        private static bool Implements(CodeNamespace cns, CodeTypeDeclaration type, string fqinterface)
        {
            Debug.Assert(type.BaseTypes != null, "CodeTypeDeclaration.BaseTypes returns null.");
            Stopwatch sw = Stopwatch.StartNew();
            Stack<IEnumerator> basetypes = new Stack<IEnumerator>();
            IEnumerator e = type.BaseTypes.GetEnumerator();
            basetypes.Push(e);
            
            // Work until there is nothing in the stack.
            while (basetypes.Count != 0)
            {                
                bool nextframe = false;
                IEnumerator enumerator = basetypes.Pop();
                try
                {                    
                    // Try to find the target in first level.
                    while (enumerator.MoveNext())
                    {
                        CodeTypeReference tref = (CodeTypeReference)enumerator.Current;
                        if (tref.BaseType == fqinterface)
                        {
                            sw.Stop();
                            Debug.Print("@ImplementsOpt: for " + type.Name + ":" + sw.ElapsedTicks.ToString());
                            return true;
                        }
                    }

                    // Item is not found in the first level so reset the enumerator for the deep scan.
                    enumerator.Reset();
                    while (enumerator.MoveNext())
                    {
                        // Does this CodeTypeReference refer to a type in the cns?
                        CodeTypeReference tref = (CodeTypeReference)enumerator.Current;
                        foreach (CodeTypeDeclaration t in cns.Types)
                        {
                            if (t.Name == tref.BaseType)
                            {
                                if (t.BaseTypes.Count > 0)
                                {
                                    basetypes.Push(enumerator); // Push the current enumerator back to the stack.
                                    basetypes.Push(t.BaseTypes.GetEnumerator()); // Push the next enumerator to the stack.                                    
                                    nextframe = true;
                                }
                                break;
                            }
                        }
                        if (nextframe)
                            break;
                    }
                }
                finally
                {
                    // Don't disponse if we are jumping the stack frame cos we might comeback to this frame.
                    if (!nextframe)
                    {
                        // Clean the current enumerator
                        IDisposable disposable = enumerator as IDisposable;
                        if (disposable != null)
                            disposable.Dispose();
                        // Dispose any other enumerators in the stack.
                        while (basetypes.Count != 0)
                        {
                            disposable = basetypes.Pop() as IDisposable;
                            if (disposable != null)
                                disposable.Dispose();
                        }
                    }
                }
            }
            return false;
        }               


        public static void RemoveDefaultValueAttributes(CodeNamespace cns)
        {
            foreach (CodeTypeDeclaration type in cns.Types)
            {
                foreach (CodeTypeMember member in type.Members)
                {
                    if (!(member is CodeMemberField))
                        continue;

                    int i = 0;
                    while (i < member.CustomAttributes.Count)
                    {
                        CodeAttributeDeclaration currentAttribute = member.CustomAttributes[i];

                        if (currentAttribute.Name == @"System.ComponentModel.DefaultValueAttribute")
                        {
                            member.CustomAttributes.Remove(currentAttribute);
                        }
                        else
                        {
                            i++;
                        }
                    }
                }
            }
        }

        #endregion

	}
}

internal class CodeAttributeArgumentExtended : CodeAttributeArgument
{
	private bool isDefault = false;

	public CodeAttributeArgumentExtended(string name, CodeExpression value) : base(name, value)
	{
	}

	public CodeAttributeArgumentExtended(CodeExpression value) : base(value)
	{
	}

	public CodeAttributeArgumentExtended(string name, CodeExpression value, bool isdefault) : base(name, value)
	{
		this.isDefault = isdefault;
	}

	public bool Default
	{
		get
		{
			return this.isDefault;
		}
		set
		{
			this.isDefault = value;
		}
	}

}
